Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When using covariance notations or generic bounds in Scala

In Scala variance can be defined with variance operators like + and - on the generic type argument. For example the List type is covariant in the standard library.

class List[+A]

So a function with a covariant list can be defined like this:

def foo[A](list : List[A])

Also variance can be emulated with generic bounds. So we can also write this

def foo[A](list : List[_:< A])

of course this makes no sense, because list is already covariant. But the same trick could be done for types that are not covariant. (like Stack). Of course, also a new types could be created from stack (inheritance of aggregation) that is covariant.

So my questions:

  1. When should be use generic bounds for variance? And when should we create a new covariant type?
  2. Are generic bounds only useful for variance, or can they declare more (language concepts).
  3. If they are only useful for variance, are bounds then only for compatibility with Java?

thx in advance :)

like image 763
Julian Avatar asked Sep 08 '10 00:09

Julian


1 Answers

If a type is naturally covariant or contravariant you should declare it so. Your users will thank you for it. The use-site variance is indeed mostly there because of Java. More precisely, a type such as Array[T <: Number] is treated as a shorthand for an existential type:

ArrayBuffer[T] forSome { type T <: Number }

Existential types have a pretty bulky syntax in Scala. That's sort of intentional, because we do not recommend you use them much. When would you need an existential type?

  1. To write the analogue of a Java type with wildcards, such as List<? extends Number>.
  2. To write the analogue of a Java raw type, such as List.

In Java, raw types and wildcard types are not quite the same and neither is quite the same as an existential type (even though we know what they are not, it's pretty hard to state precisely what they are). But they are close enough to existentials in practice, so that Scala gets away with mapping them to this kind of type.

like image 84
Martin Odersky Avatar answered Oct 04 '22 20:10

Martin Odersky