I saw the answer to the question: Can all usages of forSome
be replaced by an equivalent usage of _
?,
but didn't understand what is the real case where "_" can't be used instead of "forSome".
I read in Programming in Scala book that:
Existential types are a fully supported part of the language, but in practice they are mainly used when accessing Java types from Scala. I created Scala project and referenced Java one to it:
Scala:
object Main {
def main(args: Array[String]): Unit = {
type Test = java.util.Collection[T] forSome { type T }
val contents: Test = (new Wild).contents
type Test2 = java.util.Collection[_]
val contents2: Test2 = (new Wild).contents
// foo((new Wild).contents2) // won't compile
foo1((new Wild).contents2)
foo1((new Wild).contents3)
foo2((new Wild).contents3)
}
def foo(xs: java.util.Map[T, T] forSome { type T }) {}
def foo1(xs: java.util.Map[_, _]) {}
def foo2(xs: java.util.Map[_, _ <: java.lang.Number]) {}
}
Java:
public class Wild {
public Collection<?> contents() {
return null;
}
public Map<?, ?> contents2() {
return null;
}
public Map<?, ? extends Number> contents3() {
return null;
}
}
In all cases I was able to replace "forSome" with "_". So what are real cases where "forSome" is necessary? Please provide simple working example.
Here is rather simple example.
val listOfSets: List[Set[T]] forSome { type T } = List(Set(1, 2, 3), Set(4, 5, 6))
Note that I'm only able to store sets of the same contained type into the list. I cannot do e.g. this:
val listOfSets: List[Set[T]] forSome { type T } = List(Set(1, 2, 3), Set("a", "b", "c"))
The type of listOfSets
is inexpressable without forSome
. Indeed,
val listOfSets2: List[Set[_]]
is equivalent to
val listOfSets2: List[Set[T] forSome { type T }]
and this means that the list can contain sets of different types, so both of these work:
val listOfSets2: List[Set[_]] = List(Set(1, 2, 3), Set(4, 5, 6))
val listOfSets2: List[Set[_]] = List(Set(1, 2, 3), Set("a", "b", "c"))
It is interesting that if you run Scala interpreter as scala -feature
and try to execute the very first line of code from this answer, you will get a warning exactly about inexpressability of existential type with wildcards:
scala> val listOfSets: List[Set[T]] forSome { type T } = List(Set(1, 2, 3), Set(4, 5, 6))
<console>:7: warning: the existential type List[Set[T]] forSome { type T }, which cannot be expressed by wildcards, should be enabled
by making the implicit value scala.language.existentials visible.
This can be achieved by adding the import clause 'import scala.language.existentials'
or by setting the compiler option -language:existentials.
See the Scala docs for value scala.language.existentials for a discussion
why the feature should be explicitly enabled.
val listOfSets: List[Set[T]] forSome { type T } = List(Set(1, 2, 3), Set(4, 5, 6))
^
listOfSets: List[Set[T]] forSome { type T } = List(Set(1, 2, 3), Set(4, 5, 6))
There is another example. Suppose you want to map a class to a single instance of that class. This can be expressed with this type:
val classInstanceMap: Map[Class[T], T] forSome { type T }
Without forSome
you can't write the correct type out - there is no other way to "relate" types of keys and values. For example, this type with wildcards:
val invalidClassInstanceMap: Map[Class[_], _]
is equivalent to
val invalidClassInstanceMap: Map[Class[K] forSome { type K }, V] forSome { type V }
Here K
and V
are not related at all, moreover, keys can be arbitrary instances of Class[T]
for arbitrary T
, but all values should have the same type.
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