Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Real example of "Can all usages of `forSome` be replaced by an equivalent usage of `_`?"

Tags:

scala

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.

like image 489
user4298319 Avatar asked May 03 '14 18:05

user4298319


1 Answers

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.

like image 88
Vladimir Matveev Avatar answered Oct 03 '22 09:10

Vladimir Matveev