Search code examples
scalagenericsrecursiontype-safety

Has Scala a better way to express "self recursive generic types"?


There's a common Java idiom (seen in Enum for example) to declare a generic type variable that has to match the actual derived type.

class Enum<E extends Enum<E>> {
...
}

or, if needed more generic arguments:

abstract class Foo<T, Actual extends Foo<T, Actual>> {
    //now we can refer to the actual type
    abstract Actual copy();
}
class Concrete<T> extends Foo<T, Concrete<T>> {
    Concrete<T> copy() {...}
}

Things can get very verbose really quickly, so I imagined that Scala might have something nicer than a literal translation of the examples above.

Are there any more elegant ways to achieve this?


Solution

  • An alternative formulation is to use abstract type members:

    trait Foo { self => 
      type A <: Foo {type A = self.A}
    }
    

    With your example:

    trait Foo { self =>
      type T
      type Actual <: Foo {type T = self.T; type Actual = self.Actual}
    }
    
    trait Concrete extends Foo { self =>
      type T
      type Actual = Concrete {type T = self.T}
    }
    

    While this reformulation isn't really nicer at the trait/class declarations, when using the traits/classes it can be much terser. (And as far as I know, there isn't another way to reformulate recursive types).