What works (Part A)
Suppose I have a trait with a type parameter:
trait A[T]
I can use an existential type to write a method that will take a collection of A
s that all have the same T
:
def foo(as: Seq[A[X]] forSome { type X }) = true
Note that this is different from the following:
def otherFoo(as: Seq[A[X] forSome { type X }]) = true
Or the equivalent:
def otherFoo(as: Seq[A[_]]) = true
In these cases the scope of the existential is inside the Seq
, so the A
s can have different T
s. With my original foo
(with the existential scoping over the Seq
), the following is fine:
foo(Seq(new A[Int] {}, new A[Int] {}))
But make the type parameters different and it doesn't compile:
scala> foo(Seq(new A[Int] {}, new A[String] {}))
<console>:10: error: type mismatch;
found : Seq[A[_ >: java.lang.String with Int]]
required: Seq[A[X]] forSome { type X }
foo(Seq(new A[Int] {}, new A[String] {}))
^
This is all pretty straightforward.
What works (Part B)
Now suppose I have a similar trait with a type member instead of a type parameter:
trait B { type T }
I can write a method that will only take a B
with some specified T
:
scala> def bar[X](b: B { type T = X }) = true
bar: [X](b: B{type T = X})Boolean
scala> bar[Int](new B { type T = Int })
res5: Boolean = true
scala> bar[String](new B { type T = Int })
<console>:10: error: type mismatch;
found : java.lang.Object with B
required: B{type T = String}
bar[String](new B { type T = Int })
^
Again, this works exactly the way you'd expect it to.
What doesn't work
When we try to write the equivalent of our foo
above, but for type members, things get weird.
scala> def baz(bs: Seq[B { type T = X }] forSome { type X }) = true
baz: (as: Seq[B{type T = X}] forSome { type X })Boolean
scala> baz(Seq(new B { type T = Int }, new B { type T = String }))
res7: Boolean = true
That the last line compiles makes no sense to me. I've told it that I want all the type members to be the same. My foo
shows that I can do this for type parameters, and bar
shows that I can constrain a type based on its type members. But I can't combine the two.
I've tried this on 2.9.2 and 2.10.0-M5.
Motivation
This question is inspired by this one, where my first thought was, oh, just use an existential type (setting aside for a second the issue that it seems to be impossible to get an existential type to scope of the type of a repeated parameter, which would be handy here):
def accept(rs: Seq[RList[Int] { type S = X }] forSome { type X }) = true
But this doesn't actually work—you get the same weird result as in the simplified example above.