Majakovskij
Majakovskij

Reputation: 575

Is it possible to equal abstract type members in Scala?

An advantage of generic type parameters over abstract type members seems to be that the former can be equalled, for example:

trait A[X]
trait B[Y]
trait C[Z] extends A[Z] with B[Z]

Similarly:

trait C[Z] {
    self: A[Z] with B[Z] =>
}

The assignment of the type parameters says in fact three things: X = Z, Y = Z, and hereby X = Y.

The first case can be represented analogously:

trait A { type X }
trait B { type Y }
class C extends A with B { type X = Z; type Y = Z; type Z }

However, is something like the second case possible with abstract type members? The following solution won't work since type "Z" cannot be referred to from the self-type definition, which itself must come first:

trait C {
  self: A with B { type X = Z; type Y = Z } =>
  type Z
}

Strangely, the following seems to compile even if the type requirement of "b" is obviously violated:

trait C2 {
    val a: A { type X = Z }
    val b: B { type Y = Z }
    type Z
}

class A2 extends A { type X = Int }
class B2 extends B { type Y = String }
class D extends C2 {
    override val a = new A2
    override val b = new B2
    type Z = Int
}

Upvotes: 2

Views: 123

Answers (1)

lmm
lmm

Reputation: 17431

You can use a witness that the type parameters are equal, either =:= or scalaz.Leibniz.=== (which is more general, but means depending on scalaz).

class C extends A with B { type Z; val w1: X =:= Z; val w2: Y =:= Z }

Then there is no way to instantiate this if the types are not equal, and you can use w1 and w2 to "convert" values of type X or Y to type Z.

Upvotes: 2

Related Questions