Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala collection standard practice

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)

like image 835
oxbow_lakes Avatar asked Mar 23 '09 21:03

oxbow_lakes


2 Answers

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")

like image 184
James Iry Avatar answered Oct 08 '22 14:10

James Iry


Mutable collections are useful occasionally (though I agree that you should always look at the immutable ones first). If using them, I tend to write

import scala.collection.mutable 

at the top of the file, and (for example):

val cache = new mutable.HashMap[String, Int] 

in my code. It means you only have to write “mutable.HashMap”, not scala.collection.mutable.HashMap”. As the commentator above mentioned, you could remap the name in the import (e.g., “import scala.collection.mutable.{HashMap => MMap}”), but:

  1. I prefer not to mangle the names, so that it’s clearer what classes I’m using, and
  2. I use ‘mutable’ rarely enough that having “mutable.ClassName” in my source is not an undue burden.

(Also, can I echo the ‘avoid nulls’ comment too. It makes code so much more robust and comprehensible. I find that I don’t even have to use Option as much as you’d expect either.)

like image 37
andrewf Avatar answered Oct 08 '22 13:10

andrewf