I had already asked something about type projections here, but I have some additional questions. Consider the this example:
case class TypeT[T](m:T):
def doA: String = m.toString
trait Abstract:
type I
type T = TypeT[I]
def make:T
case class Concrete() extends Abstract:
override type I = Int
override type T = TypeT[Int]
def make:T = TypeT(1)
def use(a: Abstract): a.T =
a.make
Imagine I want to have a function that can use an Abstract
so:
def usePartOf(at:Abstract#T):String =
at.doA
val c1 = Concrete()
val o1 = use(c1)
val b1 = usePartOf(o1)
This won’t compile because type projections on abstract types have been removed. I get the following errors:
[error] -- [E008] Not Found Error: /home/hmf/VSCodeProjects/pdm_toyadmos/dcase2020/src/examples/cats/QMessage.scala:36:5
[error] 36 | at.doA
[error] | ^^^^^^
[error] | value doA is not a member of examples.cats.Abstract#T
[error] -- [E007] Type Mismatch Error: /home/hmf/VSCodeProjects/pdm_toyadmos/dcase2020/src/examples/cats/QMessage.scala:44:19
[error] 44 |val b1 = usePartOf(o1)
[error] | ^^
[error] |Found: (examples.cats.o1 : examples.cats.c1.T)
[error] |Required: examples.cats.Abstract#T²
[error] |
[error] |where: T is a type in class Concrete which is an alias of examples.cats.TypeT[Int]
[error] | T² is a type in trait Abstract which is an alias of examples.cats.TypeT[Abstract.this.I]
[error] two errors found
[error] two errors found
So my first question is: why is doA
not a member? Note that type T = TypeT[I]
and the method does not depend on the I.
My second question is: how does one actually define usePartOf
so that it can operate on any Abstract#T
? I know I can use type parameters, but it seems like this type projecton restriction makes it hard to take advantage of abstract type members (I have to keep declaring types with type paremeters, even when they are not necessary (in this case type I
)).
TIA.