I’m studying the source code of the Scala 2.8 collection classes. I have questions about the hierarchy of scala.collection.Traversable. Look at the following declarations:
package scala.collection
trait Traversable[+A]
extends TraversableLike[A, Traversable[A]]
with GenericTraversableTemplate[A, Traversable]
trait TraversableLike[+A, +Repr]
extends HasNewBuilder[A, Repr]
with TraversableOnce[A]
package scala.collection.generic
trait HasNewBuilder[+A, +Repr]
trait GenericTraversableTemplate[+A, +CC[X] <: Traversable[X]]
extends HasNewBuilder[A, CC[A] @uncheckedVariance]
Question: Why does Traversable extend GenericTraversableTemplate with type parameters [A, Traversable] – why not [A, Traversable[A]]? I tried some experimenting with a small program with the same structure and got a strange error message when I tried to change it to Traversable[A]:
error: Traversable[A] takes no type parameters, expected: one
I guess that the use of the @uncheckedVariance annotation in GenericTraversableTemplate also has to do with this? (That seems like a kind of potentially unsafe hack to force things to work…).
edit – found some useful answers about the annotation in this question (it is because GenericTraversableTemplate is used for both mutable and immutable collections which have different variance).
Question: When you look at the hierarchy, you see that Traversable inherits HasNewBuilder twice (once via TraversableLike and once via GenericTraversableTemplate), but with slightly different type parameters. How does this work exactly? Why don’t the different type parameters cause an error?
The reason is the
CCparameter in theGenericTraversableTemplatetrait. Unlike a normal type parameter which has kind*(pronounced “type”), this parameter has type* => *(pronounced “type to type”). In order to understand what this means, you first need to have a little background about kinds.Consider the following snippet:
Here we see
42, which is a value. Values have intrinsic types. In this case, our value is42and the type isInt. A type is something like a category which encompasses many values. It says something about the values which are possible for variablea. For example, we know thatacannot contain the value"foobar", because that value has typeString. Thus, values are sort of like the first level of abstraction, while types are one level above values.So here’s the question: what’s stopping us from taking this one step further? If values can have types, why can’t types have “something” above them? That “something” is called a kind. Kinds are to types what types are to values, generic categories which restrict what sort of types can be described.
Let’s look at some concrete examples:
These are types, and they all have kind
*. This is the most common kind (which is why we call it “type”). In practice, most types have this kind. However, some do not:Here we have the type constructor
List, but this time we “forgot” to specify its type parameter. As it turns out, this is actually a type, but one of a different kind. Specifically,* => *. As the notation is meant to imply, this kind describes a type which takes another type of kind*as a parameter, producing a new type of kind*as a result. We can see this in the first example, where we passed theInttype (which has kind*) to theListtype constructor (which has kind* => *), producing the typeList[Int](which has kind*).Returning to
GenericTraversableTemplate, let’s look again at the declaration:Notice how the
CCtype parameter takes a parameter of its own, but that parameter is not defined by any other type parameter in the declaration? This is Scala’s rather clumsy way of saying thatCCmust be of kind* => *(just likeamust be of typeIntin our earlier example). “Normal” type parameters (such asA) are always of kind*. By forcingCCto be of kind* => *, we’re effectively telling the compiler that the only valid types which can be substituted for this parameter must be themselves of kind* => *. Thus:Remember,
Listis of kind* => *(exactly what we need forCC), butList[Int]has kind*, so the compiler rejects it.For the record,
GenericTraversableTemplateitself has a kind, specifically:(* x (* => *)) => *. This means thatGenericTraversableTemplateis a type which takes two types as parameters — one of kind*, the other of kind* => *— and produces a type of kind*as a result. In our example above,GenericTraversableTemplate[String, List]is one such result type, and as we computed, it is of kind*(it takes no parameters).