Here is a simple example:
trait Sup {
type A
def a: A
def b: A
}
trait Sub1 extends Sup {
override type A = Product
override def a = "s" -> "s"
}
trait Sub2 extends Sup {
override type A = Serializable
override def b = "s" -> "s"
}
object SS extends Sub1 with Sub2
Obviously it will cause a compilation error, as both override type A are mutually exclusive. This is counter-intuitive as Product & Serializable are commonly used together. Alternatively, I can define:
trait Sup {
type A
def a: A
}
trait Sub1 extends Sup {
override type A <: Product
override def a = "s" -> "s"
}
trait Sub2 extends Sup {
override type A <: Serializable
override def b = "s" -> "s"
}
object SS extends Sub1 with Sub2 {
override type A = Product with Serializable
}
This makes definition of a and b invalid, as type A hasn't been reified, in addition, the line override type A = Product with Serializable is clearly a boilerplate and can be inferred instead.
What is the correct way to define an abstract type that allows diamond mixin, while avoid the boilerplate to explicitly define it in every implementations?
I guess you lost lower bounds.
"s" -> "s"has type(String, String), which is a subtype ofProduct(andSerializable) but not a subtype ofA <: Product(orA <: Serializable).Try
If you specify return type of
Sub1#a,Sub2#bto beA(above they were inferred to be(String, String)i.e. return type was narrowed upon method overriding) thenYou can do even