I have been reading about Dotty, since it looks like it is about to become scala 3, and noticed that type projections are deemed \"unsound\" and removed from the language ..
In Scala 2.12 type projections sometimes can be replaced with type class + path-dependent types
trait ContentType[T <: Container[_]] {
type Out
}
object ContentType {
type Aux[T <: Container[_], Out0] = ContentType[T] { type Out = Out0 }
def instance[T <: Container[_], Out0]: Aux[T, Out0] = new ContentType[T] { type Out = Out0 }
implicit def mk[T <: Contents]: Aux[Container[T], T] = instance
}
abstract class Manager[T <: Container[_]](implicit val contentType: ContentType[T]) {
type ContainerType = T
def getContents: contentType.Out
def createContainer(contents: contentType.Out): ContainerType
}
Checked in Dotty 0.16.0-bin-20190529-3361d44-NIGHTLY (in 0.16.0-RC3 delegate
should be instead of implied
)
trait Contents
class Foo extends Contents
class Bar extends Contents
trait Container[T <: Contents] { type ContentType = T }
class FooContainer extends Container[Foo]
class BarContainer extends Container[Bar]
trait ContentType[T <: Container[_]] {
type Out
}
object ContentType {
implied [T <: Contents] for ContentType[Container[T]] {
type Out = T
}
}
trait Manager[T <: Container[_]] given (val contentType: ContentType[T]) {
type ContainerType = T
type ContentType = contentType.Out
def getContents: ContentType
def createContainer(contents: ContentType): ContainerType
}
One more option is to use match types
trait Contents
class Foo extends Contents
class Bar extends Contents
trait Container[T <: Contents] { type ContentType = T }
class FooContainer extends Container[Foo]
class BarContainer extends Container[Bar]
type ContentType[T <: Container[_]] = T match {
case Container[t] => t
}
trait Manager[T <: Container[_]] {
type ContainerType = T
def getContents: ContentType[T]
def createContainer(contents: ContentType[T]): ContainerType
}