scalapath-dependent-typeabstract-type

Why is it possible to define a class with a unreified path-dependent type?


Considering the following example:

trait Supe {

  type Out <: Supe
  def out: Out
}

class Reif1 extends Supe {

  type Out = Reif1
  override def out: Out = this
}

class Reif2 extends Supe {

  type Out >: this.type <: Reif2
  override def out: Out = this
}

class Reif1 should obviously work. as type Out is reified and becomes a type alias

class Reif2 also works but seriously? type Out only has upper/lower bound defined and the bound was not even tight enough: this.type is a singleton type, and Reif2 is a class type. So what exactly would Out look like if Reif2 got instantiated? Is it going to be this.type? Or Reif2? But the bigger question should be: why scalac 2.12/2.13 allows it be compiled?


Solution

  • In Scala (or in DOT calculus 1 2) all types are intervals.

    type Out = Reif1 is (or is supposed to be) type Out >: Reif1 <: Reif1.

    Abstract type without bounds type Out is type Out >: Nothing <: Any.

    So what exactly would Out look like if Reif2 got instantiated?

    It will remain exactly type Out >: this.type <: Reif2

    val r = new Reif2
    
    import scala.reflect.runtime.universe._
    typeOf[r.Out] // App.r.Out
    showRaw(typeOf[r.Out]) // TypeRef(SingleType(ThisType(App), TermName("r")), TypeName("Out"), List())
    typeOf[r.Out].typeSymbol.isAbstract // true
    typeOf[r.Out].typeSymbol.typeSignature //  >: Reif2.this.type <: App.Reif2
    

    If you replace type Out >: this.type <: Reif2 in Reif2 with type Out = this.type (or type Out = Reif2 or type Out = Supe) then isAbstract will return false.

    Abstract type member of a singleton object (see application of abstract type)

    What is the meaning of a type declaration without definition in an object? (see why it's not easy to check that type T >: L <: U is not abstract)

    Concrete classes can have abstract type members #1753

    SI-8217 allow abstract type members in objects #4024

    Abstract type members are incorrectly forbidden in objects (unless inherited) #8217

    Use of abstract type in a concrete class?

    Concrete classes with abstract type members

    What's different between "def apply[T](c:T)" and "type T;def apply(c:T)"