Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
696 views
in Technique[技术] by (71.8m points)

scala - Is it possible to override a type field?

scala> class C
defined class C

scala> class subC extends C
defined class subC

scala> class A { type T = C}
defined class A

scala> class subA extends A { override type T = subC}
<console>:10: error: overriding type T in class A, which equals C;
 type T has incompatible type
      class subA extends A { override type T = subC}
                                           ^

In the example above, I get an error message, that I can not override the type field in class A ( even if the chosen type subC extends the class C).

Is overriding a type field possible at all ? And if yes, what is wrong with the example above ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You wouldn't speak of 'overriding' with respect to types, but rather narrowing their bounds.

  1. type T ... no bounds
  2. type T <: C ... T is C or a subtype of C (which is called upper bound)
  3. type T >: C ... T is C or a supertype of C (which is called lower bound)
  4. 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 {}
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...