Update: Thanks to gerferra (see comment below) I have added a paragraph explaining that you should use chained package clauses in combination with retargeting
One of Scala’s guiding principles is its bias towards immutability: While we can use
vars and mutable objects, we are encouraged to use
vals and immutable objects. This manifests itself very clearly in the collection library which contains both immutable and mutable collections. Actually there are three main packages:
scala.collection contains basic objects which are extended by the immutable collections in
scala.collection.immutable and the mutable ones in
It is important to understand that the basic collections are neither immutable or mutable, they just provide common functionality. If an API makes use of a basic collection, e.g. for the type of a method parameter, we can either use an immutable or mutable one for the argument.
Let’s look at a simple example:
def basicSetSize[A](as: scala.collection.Set[A]): Int = as.size
scala> basicSetSize(scala.collection.immutable.Set(1, 2, 3)) res0: Int = 3 scala> basicSetSize(scala.collection.mutable.Set(1, 2, 3)) res1: Int = 3
As you can see, we can use an immutable or a mutable
Set for a basic
Set. So far so good.
Now back to Scala’s guiding principle of immutability. In order to give preference to the immutable collections, the
Predef singleton object and the
scala package object contain a number of aliases that bring the immutable collections into scope without any imports. That means that we can use many immutable collections even if we don’t import anything from either
Let’s rewrite the above example:
def basicSetSize[A](as: Set[A]): Int = as.size
scala> basicSetSize(scala.collection.immutable.Set(1, 2, 3)) res0: Int = 3 scala> basicSetSize(scala.collection.mutable.Set(1, 2, 3)) :9: error: type mismatch; found : scala.collection.mutable.Set[Int] required: scala.collection.immutable.Set[?] scala> basicSetSize(scala.collection.Set(1, 2, 3)) :9: error: type mismatch; found : scala.collection.Set[Int] required: scala.collection.immutable.Set[?]
As you can see,
Set without imports or qualifying package essentially means
scala.collection.immutable.Set and we can’t use a mutable or basic
Now this is expected, because Scala is encouraging us to use immutable objects. Many think that this principle holds for all major collections types, but this is not true! Guess where the aliases for
Seq are pointing to: To
scala.collection.immutable.Seq like for
Set and other collections? No!
type Seq[+A] = scala.collection.Seq[A] val Seq = scala.collection.Seq
These aliases are defined in the
scala package object. The reason for this exception is, that one should be able to use arrays, which are mutable, for the “default” sequence.
Predef contains implicit conversions from
WrappedArray which mixes in various mutable collection traits.
While this makes it comfortable to work with arrays, I consider this very dangerous, because it is too easy to forget importing
scala.collection.immutable.Seq. If we forget this import and hence use the basic sequence in our API, users can provide mutable sequences which most certainly will lead to trouble in any concurrent program. Just imagine objects used as messages in an Akka based system …
If you want to be sure your code is using immutable sequences, I recommend adding the following lines to the top-level package object in your projects:
type Seq[+A] = scala.collection.immutable.Seq[A] val Seq = scala.collection.immutable.Seq
If you use chained package clauses (see below) in all your Scala source file, this will automatically “retarget”
Seq to the immutable sequence and all should be good.
package name.heikoseeberger.toplevel package subpackage