You wouldn't speak of 'overriding' with respect to types, but rather narrowing their bounds.
type T
... no bounds
type T <: C
... T
is C
or a subtype of C
(which is called upper bound)
type T >: C
... T
is C
or a supertype of C
(which is called lower bound)
type T = C
... T
is exactly C
(type alias)
Therefore, if T
is a type member of trait A
, and SubA
is a subtype of A
, in case (2) SubA
may narrow T
to a more particular subtype C
, whereas in case (3) it could narrow it to a higher supertype of C
. Case (1) doesn't impose any restrictions for SubA
, while case (4) means that T
is 'final' so to speak.
This has consequences for the useability of T
in A
—whether it may appear as a method argument's type or a method's return type.
Example:
trait C { def foo = () }
trait SubC extends C { def bar = () }
trait MayNarrow1 {
type T <: C // allows contravariant positions in MayNarrow1
def m(t: T): Unit = t.foo // ...like this
}
object Narrowed1 extends MayNarrow1 {
type T = SubC
}
object Narrowed2 extends MayNarrow1 {
type T = SubC
override def m(t: T): Unit = t.bar
}
It is possible to define method m
in MayNarrow1
because type T
occurs in contravariant position (as a method argument's type), therefore it is still valid even if T
is narrowed down in a subtype of MayNarrow1
(the method body can treat t
as if it were type C
).
In contrast, type T = C
inevitably fixes T
, which would kind of correspond to making a method final
. By fixing T
, it can be used in a covariant position (as a method's return type):
trait Fixed extends MayNarrow1 {
type T = C // make that T <: C to see that it won't compile
final def test: T = new C {}
}
You can now easily see that it must be forbidden to further 'override' T
:
trait Impossible extends Fixed {
override type T = SubC
test.bar // oops...
}
To be complete, here is the less common case of a lower bound:
trait MayNarrow2 {
type T >: SubC // allows covariant positions in MayNarrow2
def test: T = new SubC {}
}
object Narrowed3 extends MayNarrow2 {
type T = C
test.foo
}
object Narrowed4 extends MayNarrow2 {
type T = C
override def test: T = new C {}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…