Because of inheritance linearization in Scala, I would like to understand how traits I specify for a case class are ordered relative to the two traits automatically generated and added by the Scala compiler; i.e. Product with Serializable (and disappointingly, it's not ProductN[...] as of 2.12).
I've searched through pretty thoroughly and I haven't found it directly addressed. Given the following:
case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB
Following the Scala compiler automatic code generation, which of these is the correct assumption about the resulting inheritance ordering?
case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB with Product with Serializablecase class Cc(a: Int, b: Int) extends Product with Serializable with MyTraitA with MyTraitB
And then, I have an additional question. What undesirable or unexpected effects could occur if I were to explicitly extend Product2[...] to the case class? Here are the two above pieces of code repeated with Product2[...] inserted:
case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB with Product2[Int, Int] with Product with Serializablecase class Cc(a: Int, b: Int) extends Product with Serializable with MyTraitA with MyTraitB with Product2[Int, Int]
IOW, is there any sort of undesirable interactions because both Product and Product2 appear together?
Thanks to deep reading a link provided in a comment by Bogdan Vakulenko, the explicit answer to the first question is item 2:
And thanks, again, to Bogdan Vakulenko, the answer to the second question is nothing undesirable should occur when adding the
Product2[Int, Int]trait given it extends theProducttrait.There is a bonus answer which is very interesting. If it is desired to push the compiler generated interfaces to the back of the trait inheritance ordering, it's required the compiler generated interfaces instead be explicitly defined. And there are several ways to do this.
The first and simplest is to change the original code which appeared like this (no reference to
ProductnorSerializableand have the compiler automatically generate them):to appear like this (explicitly defining
ProductandSerializableat the tail of the trait list):The second option is to add
Product with Serializableto both/either ofMyTraitAand/orMyTraitBas such:This technique also results in desirable trait ordering.
Finally, integrating
Product2[Int, Int]is as simple as explicitly defining everything knowing any overlaps will be automatically resolved via the excellent multiple inheritance resolution strategies provided by default within the Scala compiler: