[英]In scala 2.13+ / 3.x, how can we address the diamond inheritance problem of abstract types?
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.显然它会导致编译错误,因为两个
override type A
是互斥的。 This is counter-intuitive as Product & Serializable are commonly used together.这是违反直觉的,因为 Product 和 Serializable 通常一起使用。 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.这使得 a 和 b 的定义无效,因为类型 A 尚未具体化,此外,行
override type A = Product with Serializable
显然是一个样板,可以改为推断。
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 of Product
(and Serializable
) but not a subtype of A <: Product
(or A <: Serializable
). "s" -> "s"
具有类型(String, String)
,它是Product
(和Serializable
)的子类型,但不是A <: Product
(或A <: Serializable
)的子类型。
Try尝试
trait Sup {
type A
def a: A
def b: A
}
trait Sub1 extends Sup {
override type A >: (String, String) <: Product
override def a = "s" -> "s"
}
trait Sub2 extends Sup {
override type A >: (String, String) <: Serializable
override def b = "s" -> "s"
}
object SS extends Sub1 with Sub2 {
override type A = Product with Serializable
}
SS.a: (String, String)
SS.b: (String, String)
implicitly[SS.A =:= (Product with Serializable)]
If you specify return type of Sub1#a
, Sub2#b
to be A
(above they were inferred to be (String, String)
ie return type was narrowed upon method overriding) then如果您将
Sub1#a
、 Sub2#b
返回类型指定为A
(以上它们被推断为(String, String)
即返回类型在方法覆盖时被缩小)然后
trait Sup {
type A
def a: A
def b: A
}
trait Sub1 extends Sup {
override type A >: (String, String) <: Product
override def a: A = "s" -> "s"
}
trait Sub2 extends Sup {
override type A >: (String, String) <: Serializable
override def b: A = "s" -> "s"
}
object SS extends Sub1 with Sub2 {
override type A = Product with Serializable
}
SS.a: Product with Serializable
SS.b: Product with Serializable
implicitly[SS.A =:= (Product with Serializable)]
You can do even你甚至可以做
object SS extends Sub1 with Sub2 {
override type A >: (String, String) <: Product with Serializable
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.