Based on the answers to this question, it appears that placing "forSome" after a component of the type definition is different from placing it at the end of the whole thing. For instance, it seems there is a difference between the following:
def one: Foo[U >: T] forSome {type U >: T}
def one: Foo[U forSome {type U >: T}]
The Scala language specification does not seem to say anything about the difference, and I would have imagined that moving the quantifiers to the outside would make no difference. If it did make a difference, I would have thought it would be as described in this answer, which basically says Set[X forSome {type X}] allows X to vary between set elements, where Set[X] forSome {type X} does not. However, this does not seem to be the whole story and/or is not correct, because this does not compile:
trait Bar {
def test: Set[X] forSome {type X}
}
def test(b: Bar) {
val set = b.test
val h = set.head
set.contains(h)
}
But this does:
trait Bar {
def test: Set[X forSome {type X}]
}
def test(b: Bar) {
val set = b.test
val h = set.head
set.contains(h)
}
It seems as if Set[X] forSome {type X} creates a separate abstract type for every usage site in the instantiated class, where Set[X forSome {type X}] creates only one and uses it for the entire class. This is the opposite of what I would have expected and seems inconsistent with the answer reference above.
A couple of observations to start with: X forSome { type X }
is just a fancy way of writing Any
—it's a type we don't know anything about, so it must be at the top of the type hierarchy. If you don't believe me, ask the compiler:
scala> implicitly[Any =:= X forSome { type X }]
res0: =:=[Any, _] = <function1>
Yep, it agrees.
Relatedly, the following won't compile:
scala> val xs: Set[X forSome { type X }] = Set[Int](1, 2, 3)
<console>:7: error: type mismatch;
found : scala.collection.immutable.Set[Int]
required: Set[X forSome { type X }]
Note: Int <: X forSome { type X }, but trait Set is invariant in type A.
Which isn't surprising given what we just learned. Set
is invariant in its type parameter, so a Set[Int]
isn't a Set[X forSome { type X }]
(i.e., a Set[Any]
).
Given all of this it's also not too surprising that the second test
method compiles. When we take the head of b.test
, we get an X forSome { type X }
(i.e., an Any
), and we need an X forSome { type X }
(i.e., an Any
) for b.test.contains
.
So now for the first Bar
. Consider the following:
scala> val xs: Set[X] forSome { type X } = Set[Int](1, 2, 3)
xs: Set[_] = Set(1, 2, 3)
Here we've said xs
is a set of some specific type X
, but we're immediately going to forget everything about X
. Note that unlike the xs
definition above, this does compile, since we're not saying that xs
is a set of anything, just that it's a set of some specific type we don't know (or rather that the compiler doesn't know).
This means that there's absolutely no possible a
that will make xs.contains(a)
compile. Let's try an obvious one:
scala> xs.contains(1)
<console>:9: error: type mismatch;
found : Int(1)
required: X
xs.contains(1)
^
The error message here is interesting—we know that X
is actually Int
, but the compiler doesn't, since we explicitly asked it to forget that fact with the forSome { type X }
. You can see a similarly interesting message by rewriting your test
method for the first Bar
as follows:
def test(b: Bar) = b.test.contains(b.test.head)
This also won't compile, with the following message:
found : (some other)X(in method test) where type (some other)X(in method test)
required: X(in method test) where type X(in method test)
def test(b: Bar) = b.test.contains(b.test.head)
^
That is, even though we just pulled that b.test.head
out of b.test
, we still can't apply b.test.contains
to it. We've told the compiler that the only thing it knows about the item type of b.test
is that it exists, so it's not going to keep track of the fact that b.test.head
is the kind of thing that we should be able to apply b.test.contains
to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With