2

I have some case classes that extend a common superclass and I'd like to access fields from the superclass using productElement method (I've tryed to declare base class as a case class but I get a frightening warning about the dangers of inheritance of case classes and yet doesn't work).

I can imagine some solution like this:

abstract class A(a: Int) extends Product { def productArity = 1 def productElement(n: Int) = if (n == 0) a else throw new IndexOutOfBoundsException } case class B(b: Int) extends A(1) { def productArity = super.productArity + 1 def productElement(n: Int) = if (n < super.productArity) super.productElement(n) else .... } 

but it was getting so ugly that I can't even finish.

Does anybody know a better solution?

2
  • Can you make A an abstract case class? Commented Oct 31, 2011 at 15:27
  • Yes, I've done it and I get this: Case-to-case inheritance has potentially dangerous bugs which are unlikely to be fixed. You are strongly encouraged to instead use extractors to pattern match on non-leaf nodes. Besides it doesn't work. Commented Oct 31, 2011 at 16:38

2 Answers 2

4

In Scala trunk a lot of this is done for you already: case classes now extend the appropriate ProductN trait. Only case class direct (ie. not inherited) members are included in the product however, so if you need to include members from a super type, they would have to be abstract in the super type and given a concrete implementation in the case class.

Here's a REPL session (Scala trunk, 2.10.0.r25951-b20111107020214),

scala> trait A { val a: Int } defined trait A scala> case class B(b: Int, a : Int = 1) extends A defined class B scala> val b = B(23) b: B = B(23,1) scala> b.productArity res0: Int = 2 scala> b.productElement(0) res1: Any = 23 scala> b.productElement(1) res2: Any = 1 scala> b._1 // use Product method ... note result type res6: Int = 23 scala> b._2 // use Product method ... note result type res7: Int = 1 
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, your solution looks nicer than the previous one (abstract class), but I still can't figure out a way to put inherited members at first positions. I'd like to avoid some clumsy code like x.productElement( x.productArity - 1 )
For some reason, this was dropped in 2.10. Do you know why?
@Blaisorblade I forget the details the devil was hiding in, but you can follow progress (or the lack thereof) here.
1

The closest I can get is to not implement anything in A

scala> abstract class A(val a: Int) extends Product defined class A scala> case class B(override val a: Int, b: String) extends A(a) defined class B scala> val anA: A = B(42, "banana") anA: A = B(42,banana) scala> anA.a res37: Int = 42 scala> anA.productArity res38: Int = 2 scala> anA.productElement(1) res39: Any = banana scala> anA.productElement(0) res40: Any = 42 

1 Comment

Thanks for the idea! It led me to this other solution: abstract class A(val a: Int) extends Product case class B(b: String, override val a: Int = 42) extends A(a) the only drawback is that 'a' won't be in the same position for all subclasses.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.