In Scala 2, you can of course use use wildcard or existential types as type arguments. However, this means that you do not always have a name for a type you'd like to use. This sometimes leads to odd situations where you need to lean on type inference to circumvent writing a type explicitly.
Here is a somewhat contrived example of what I mean:
case class Container[T](value: T) {
def replace(value: T): Container[T] = Container(value)
}
def identity[T](container: Container[T]): Container[T] = {
// A weird way of writing the identity function,
// but notice that I have essentially given the name
// `T` to the `_`
container.replace(container.value)
}
var x: Container[_] = Container[Int](1)
// This works, but as far as I know, there's no way to explicitly
// pass the type for `T`. For example, something like identity[_](x) won't work.
identity(x)
// This also fails to work, but if we could assign a name to the `_`, like `T`,
// then it would become obvious that this should work.
// x.replace(x.value)
Is there a way to get around this more cleanly? It would be really great if you could write something like:
let Container[T] = x.type in {
// Now there is a type T in this scope,
// and x has type `Container[T]`
}
As far as I'm aware, nothing of the sort exists in Scala. Is there a feature I'm missing. Also, does anyone know of similar features in other languages?
Use type pattern matching (tested with 2.13):
case class Container[T](value: T) {
def replace(value: T): Container[T] = Container(value)
}
val x: Container[_] = Container[Int](1)
val y: Container[_] = x match {
case c => c.replace(c.value)
}
The actual type itself does not have a name in code, and isn't actually visible, but what's basically happening is this:
case class Container[T](value: T) {
def replace(value: T): Container[T] = Container(value)
}
val x: Container[_] = Container[Int](1)
val y: Container[_] = x match {
case c: Container[t] =>{
val v: t = c.value
c.replace(v)
}
}
The type pattern t
binds the existentially quantified type, and can be used in subsequent expressions, so that v: t
can be typed, and c.replace(v)
is also properly typed.
See also the following related questions: