Scala collection standard practice

oxbow_lakes picture oxbow_lakes · Mar 23, 2009 · Viewed 9.5k times · Source

Coming from a Java background, I'm used to the common practice of dealing with collections: obviously there would be exceptions but usually code would look like:

public class MyClass {
  private Set<String> mySet;

  public void init() {
    Set<String> s = new LinkedHashSet<String>();
    s.add("Hello");
    s.add("World"); 
    mySet = Collections.unmodifiableSet(s);
  }
}

I have to confess that I'm a bit befuddled by the plethora of options in Scala. There is:

  • scala.List (and Seq)
  • scala.collections.Set (and Map)
  • scala.collection.immutable.Set (and Map, Stack but not List)
  • scala.collection.mutable.Set (and Map, Buffer but not List)
  • scala.collection.jcl

So questions!

  1. Why are List and Seq defined in package scala and not scala.collection (even though implementations of Seq are in the collection sub-packages)?
  2. What is the standard mechanism for initializing a collection and then freezing it (which in Java is achieved by wrapping in an unmodifiable)?
  3. Why are some collection types (e.g. MultiMap) only defined as mutable? (There is no immutable MultiMap)?

I've read Daniel Spiewak's excellent series on scala collections and am still puzzled by how one would actually use them in practice. The following seems slightly unwieldy due to the enforced full package declarations:

class MyScala {
  var mySet: scala.collection.Set[String] = null 

  def init(): Unit = {
     val s = scala.collection.mutable.Set.empty[String]
     s + "Hello"
     s + "World"
     mySet = scala.collection.immutable.Set(s : _ *)

  }
}

Although arguably this is more correct than the Java version as the immutable collection cannot change (as in the Java case, where the underlying collection could be altered underneath the unmodifiable wrapper)

Answer

James Iry picture James Iry · Mar 23, 2009

Why are List and Seq defined in package scala and not scala.collection (even though implementations of Seq are in the collection sub-packages)?

Because they are deemed so generally useful that they are automatically imported into all programs via synonyms in scala.Predef.

What is the standard mechanism for initializing a collection and then freezing it (which in Java is achieved by wrapping in an unmodifiable)?

Java doesn't have a mechanism for freezing a collection. It only has an idiom for wrapping the (still modifiable) collection in a wrapper that throws an exception. The proper idiom in Scala is to copy a mutable collection into an immutable one - probably using :_*

Why are some collection types (e.g. MultiMap) only defined as mutable? (There is no immutable MultiMap)?

The team/community just hasn't gotten there yet. The 2.7 branch saw a bunch of additions and 2.8 is expected to have a bunch more.

The following seems slightly unwieldy due to the enforced full package declarations:

Scala allows import aliases so it's always less verbose than Java in this regard (see for example java.util.Date and java.sql.Date - using both forces one to be fully qualified)

import scala.collection.{Set => ISet}
import scala.collection.mutable.{Set => MSet}

class MyScala {
  var mySet: ISet[String] = null 

  def init(): Unit = {
     val s = MSet.empty[String]
     s + "Hello"
     s + "World"
     mySet = Set(s : _ *)
  }
}

Of course, you'd really just write init as def init() { mySet = Set("Hello", "World")} and save all the trouble or better yet just put it in the constructor var mySet : ISet[String] = Set("Hello", "World")