Being new to scala and a current java developer, scala was designed to encourage the use of immutability to class design.
How does this translate practically to the design of classes? The only thing that is brought to my mind is case classes. Are case classes strongly encouraged for defining data? Example? How else is immutability encouraged in Scala design of classes?
As a java developer, classes defining data were mutable. The equivalent Scala classes should be defined as case classes?
Well, case classes certainly help, but the biggest contributor is probably the collection library. The default collections are immutable, and the methods are geared toward manipulating collections by producing new ones instead of mutating. Since the immutable collections are persistent, that doesn’t require copying the whole collection, which is something one often has to do in Java.
Beyond that, for-comprehensions are monadic comprehensions, which is helpful in doing immutable tasks, there’s tail recursion optimization, which is very important in immutable algorithms, and general attention to immutability in many libraries, such as parser combinators and xml.
Finally, note that you have to ask for a
varto get some mutability. Parameters are immutable, andvalis just as short asvar. Contrast this with Java, where parameters are mutable, and you need to add afinalkeyword to get immutability. Whereas in Scala it is as easy or easier to stay immutable, in Java it is easier to stay mutable.Addendum
Persistent data structures are data structures that share parts between modified versions of it. This might be a bit difficult to understand, so let’s consider Scala’s
List, which is pretty basic and easy to understand.A Scala
Listis composed of two classes, known as cons andNil. The former is actually written::in Scala, but I’ll refer to it by the traditional name.Nilis the empty list. It doesn’t contain anything. Methods that depend on the list not being empty, such asheadandtailthrow exceptions, while others work ok.Naturally, cons must then represent a non-empty list. In fact, cons has exactly two elements: a value, and a list. These elements are known as head and tail.
So a list with three elements is composed of three cons, since each cons will hold only one value, plus a
Nil. It must have aNilbecause a cons must point to a list. As lists are not circular, then one of the cons must point to something other than a cons.One example of such list is this:
Now, the components of a Scala
Listare immutable. One cannot change neither the value nor the list of a cons. One benefit of immutability is that you never need to copy the collection before passing or after receiving it from some other method: you know that list cannot change.Now, let’s consider what would happen if I modified that list. Let’s consider two modifications: removing the first element and prepending a new element.
We can remove one element with the method
tail, whose name is not a coincidence at all. So, we write:And
list2will point to the same list thatlist‘s tail is pointing. Nothing at all was created: we simply reused part oflist. So, let’s prepend an element tolist2then:We created a new cons there. This new cons has a value (a head) equal to 0, and its tail points to
list2. Note that bothlistandlist3point to the samelist2. These elements are being shared by bothlistandlist3.There are many other persistent data structures. The very fact that the data you are manipulating is immutable makes it easy to share components.
One can find more information about this subject on the book by Chris Okasaki, Purely Functional Data Structures, or on his freely available thesis by the same name.