Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to override a type field?

Tags:

types

scala

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 ?

like image 543
John Threepwood Avatar asked Jun 30 '12 14:06

John Threepwood


People also ask

Can we override a field?

Fields can't be overridden; they're not accessed polymorphically in the first place - you're just declaring a new field in each case. It compiles because in each case the compile-time type of the expression is enough to determine which field called number you mean.

Can you override a field in Java?

Java Inheritance BasicsFields cannot be overridden, but can be "shadowed" in subclasses.

Can subclasses override fields?

In any object-oriented programming language, Overriding is a feature that allows a subclass to provide a specific implementation of a method or field that is already provided by one of its super-classes.

Can we override fields in C#?

You cannot override a non-virtual or static method. The overridden base method must be virtual , abstract , or override . An override declaration cannot change the accessibility of the virtual method. Both the override method and the virtual method must have the same access level modifier.


1 Answers

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 {}
}
like image 112
0__ Avatar answered Sep 29 '22 02:09

0__