15

after I learned that case classes extend Product, I wondered why they do not extend ProductN. E.g., given a code like:

case class Foo(a: Int)

I'd expect Foo(1).asInstanceOf[Product1[Int]] to work, but it does not (checked with Scala 2.9.1, and confirmed by other sources and by Product documentation).

I was interested in this, because I wanted to declare classes such as:

abstract class UnaryOp[T1 <: Exp[_], R](t1: T1) extends Exp[R] {
  this: Product1[T1] =>
}

This way, a node for a Unary operation must be implement Product1. It would be nice if being simply a case class with one parameter would be enough for this.

Blaisorblade
  • 6,438
  • 1
  • 43
  • 76

3 Answers3

11

Consider this:

case class X(n: Int)
case class Y(x: String, y: Int) extends X(y)

If case classes extended ProductN, then that would extend both Product1 and Product2, but the type parameter changes, so there are two different overloads for _1. This is just one problem -- I bet there are others.

Now, case class inheriting case class has been deprecated, and Martin Odersky is now considering making them inherit ProductN. AFAIK, is has not been done yet, but the obstacle has been removed.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • 4
    Yes, hopefully this will make it into a future Scala version as it allows one to write type safe, generic decomposition functions of case classes. – Jesper Nordenberg Sep 08 '11 at 10:59
  • 1
    Is it possible to inherit case classes in Scala? – Taky Feb 22 '16 at 12:27
  • 1
    Given how much Scala has changed since you provided this answer, specifically the case class inheritance you describe above was deprecated my Scala versions ago (well before 2.12...the current version), the question is now open again. Is there any chance it will finally be added to the Scala 2.x line? Any chance that this has been fixed for Scala 3 (Dotty), and if so, be backported to the 2.x line? – chaotic3quilibrium May 27 '19 at 17:28
3

I brought it back shortly after martin said we could do it. It doesn't work right yet, but to the extent that it does, it's behind -Xexperimental in trunk builds.

scala> case class Foo[T, U](x1: T, x2: U)
defined class Foo

scala> Foo(List("a"), "b")
res0: Foo[List[java.lang.String],java.lang.String] = Foo(List(a),b)

scala> res0.isInstanceOf[Product2[_,_]]
res1: Boolean = true
psp
  • 12,138
  • 1
  • 41
  • 51
  • Thanks, that's great - it'd be nice to have that for next Scala release! I was unsure which answer to accept, but in that end I think I still have to accept Daniel C. Sobral's answer for providing the explanation. – Blaisorblade Sep 09 '11 at 11:43
  • I tried this out in 2.10.0-M5, with confusing results. _1 and _2 are present on Foo, but it's not a subtype of Product2, and these members are not documented by Scaladoc: ```scala> Foo(List("a"), "b") res10: Foo[List[String],String] = Foo(List(a),b) scala> res10.isInstanceOf[Product2[_,_]] res11: Boolean = false scala> res10._1 res12: List[String] = List(a) scala> Some(1)._1 res13: Int = 1``` – Blaisorblade Jul 20 '12 at 14:30
  • Whatever happened to this, given a case class inheriting from another case class was deprecated? Is there any possibility of it appearing in current 2.x versions, and/or in Scala 3 (Dotty)? – chaotic3quilibrium May 27 '19 at 17:30
0

If Product1[Int] would have been automatically extended the val _1: Int would also have to be provided. Although I could imagine, that it could be automated that a gets assigned to _1 etc etc, but it is not. Probably just not to make things even more complicated.

agilesteel
  • 16,775
  • 6
  • 44
  • 55
  • Adding `val _1: Int` would waste memory in each instance, but `Product1[T]` has an abstract definition `def _1: T`, and adding an implementation for that (`def _1: T = a`) doesn't change the instance size. See Daniel C. Sobral's answer! – Blaisorblade Sep 09 '11 at 11:41
  • 2
    What would happen here? case class C(_2: String, _1: Int) – nafg Nov 13 '12 at 10:51