Student Questions about Scala, Part 1

Topics: conventions, regexes, mapping, partitioning, vectors vs lists, overloaded constructors, case classes, traits, multiple inheritance, implicits

Preface

I’m currently teaching a course on Applied Text Analysis and am using Scala as the programming language taught and used in the course. Rather than creating more tutorials, I figured I’d take a page from Brian Dunning’s playbook on his Skeptoid podcast (highly recommended) when he takes student questions.  So, I had the students in the course submit questions about Scala that they had, based on the readings and assignments thus far. This post covers over half of them — the rest will be covered in a follow up post.

I start with some of the more basic questions, and the questions and/or answers progressively get into more intermediate level topics. Suggestions and comments to improve any of the answers are very welcome!

Basic Questions

Q. Concerning addressing parts of variables: To address individual parts of lists, the numbering of the items is (List 0,1,2 etc.) That is, the first element is called “0”. It seems to be the same for Arrays and Maps, but not for Tuples- to get the first element of a Tuple, I need to use Tuple._1. Why is that?

A. It’s just a matter of convention — tuples have used a 1-based index in other languages like Haskell, and it seems that Scala has adopted the same convention/tradition. See:

http://stackoverflow.com/questions/6241464/why-are-the-indexes-of-scala-tuples-1-based

Q. It seems that Scala doesn’t recognize the “b” boundary character as a regular expression.  Is there something similar in Scala?

A. Scala does recognize boundary characters. For example, the following REPL session declares a regex that finds “the” with boundaries, and successfully retrieves the three tokens of “the” in the example sentence.

[sourcecode lang=”scala”]
scala> val TheRE = """btheb""".r
TheRE: scala.util.matching.Regex = btheb

scala> val sentence = "She think the man is a stick-in-the-mud, but the man disagrees."
sentence: java.lang.String = She think the man is a stick-in-the-mud, but the man disagrees.

scala> TheRE.findAllIn(sentence).toList
res1: List[String] = List(the, the, the)
[/sourcecode]

Q. Why doesn’t the method “split” work on args? Example: val arg = args.split(” “). Args are strings right, so split should work?

A. The args variable is an Array, so split doesn’t work on them. Arrays are, in effect, already split.

Q. What is the major difference between foo.mapValues(x=>x.length) and foo.map(x=>x.length). Some places one works and one does not.

A. The map function works on all sequence types, including Seqs and Maps (note that Maps can be seen as sequences of Tuple2s). The mapValues function, however, only works on Maps. It is essentially a convenience function. As an example, let’s start with a simple Map from Ints to Ints.

[sourcecode lang=”scala”]
scala> val foo = List((1,2),(3,4)).toMap
foo: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 3 -> 4)
[/sourcecode]

Now consider the task of adding 2 to each value in the Map. This can be done with the map function as follows.

[sourcecode lang=”scala”]
scala> foo.map { case(key,value) => (key,value+2) }
res5: scala.collection.immutable.Map[Int,Int] = Map(1 -> 4, 3 -> 6)
[/sourcecode]

So, the map function iterates over key/value pairs. We need to match both of them, and then output the key and the changed value to create the new Map. The mapValues function makes this quite a bit easier.

[sourcecode lang=”scala”]
scala> foo.mapValues(2+)
res6: scala.collection.immutable.Map[Int,Int] = Map(1 -> 4, 3 -> 6)
[/sourcecode]

Returning to the question about computing the length using mapValues or map — then it is just a question of which values you are transforming, as in the following examples.

[sourcecode lang=”scala”]
scala> val sentence = "here is a sentence with some words".split(" ").toList
sentence: List[java.lang.String] = List(here, is, a, sentence, with, some, words)

scala> sentence.map(_.length)
res7: List[Int] = List(4, 2, 1, 8, 4, 4, 5)

scala> val firstCharTokens = sentence.groupBy(x=>x(0))
firstCharTokens: scala.collection.immutable.Map[Char,List[java.lang.String]] = Map(s -> List(sentence, some), a -> List(a), i -> List(is), h -> List(here), w -> List(with, words))

scala> firstCharTokens.mapValues(_.length)
res9: scala.collection.immutable.Map[Char,Int] = Map(s -> 2, a -> 1, i -> 1, h -> 1, w -> 2)
[/sourcecode]

Q. Is there any function that splits a list into two lists with the elements in the alternating positions of the original list? For example,

MainList =(1,2,3,4,5,6)

List1 = (1,3,5)
List2 = (2,4,6)

A. Given the exact main list you provided, one can use the partition function and use the modulo operation to see whether the value is divisible evenly by 2 or not.

[sourcecode lang=”scala”]
scala> val mainList = List(1,2,3,4,5,6)
mainList: List[Int] = List(1, 2, 3, 4, 5, 6)

scala> mainList.partition(_ % 2 == 0)
res0: (List[Int], List[Int]) = (List(2, 4, 6),List(1, 3, 5))
[/sourcecode]

So, partition returns a pair of Lists. The first has all the elements that match the condition and the second has all the ones that do not.

Of course, this wouldn’t work in general for Lists that have Strings, or that don’t have Ints in order, etc. However, the indices of a List are always well-behaved in this way, so we just need to do a bit more work by zipping each element with its index and then partitioning based on indices.

[sourcecode lang=”scala”]
scala> val unordered = List("b","2","a","4","z","8")
unordered: List[java.lang.String] = List(b, 2, a, 4, z, 8)

scala> unordered.zipWithIndex
res1: List[(java.lang.String, Int)] = List((b,0), (2,1), (a,2), (4,3), (z,4), (8,5))

scala> val (evens, odds) = unordered.zipWithIndex.partition(_._2 % 2 == 0)
evens: List[(java.lang.String, Int)] = List((b,0), (a,2), (z,4))
odds: List[(java.lang.String, Int)] = List((2,1), (4,3), (8,5))

scala> evens.map(_._1)
res2: List[java.lang.String] = List(b, a, z)

scala> odds.map(_._1)
res3: List[java.lang.String] = List(2, 4, 8)
[/sourcecode]

Based on this, you could of course write a function that does this for any arbitrary list.

Q. How to convert a List to a Vector and vice-versa?

A. Use toIndexSeq and toList.

[sourcecode lang=”scala”]
scala> val foo = List(1,2,3,4)
foo: List[Int] = List(1, 2, 3, 4)

scala> val bar = foo.toIndexedSeq
bar: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4)

scala> val baz = bar.toList
baz: List[Int] = List(1, 2, 3, 4)

scala> foo == baz
res0: Boolean = true
[/sourcecode]

Q. The advantage of a vector over a list is the constant time look-up. What is the advantage of using a list over a vector?

A. A List is slightly faster for operations at the head (front) of the sequence, so if all you are doing is doing a traversal (accessing each element in order, e.g. when mapping), then Lists are perfectly adequate and may be more efficient. They also have some nice pattern matching behavior for case statements.

However, common wisdom seems to be that you should default to using Vectors. See Daniel Spiewak’s nice answer on Stackoverflow:

http://stackoverflow.com/questions/6928327/when-should-i-choose-vector-in-scala

Q. With splitting strings, holmes.split(“\s”) – n and t just requires a single ” to recognize its special functionality but why two ”s are required for white space character?

A. That’s because n and t actually mean something in a String.

[sourcecode lang=”scala”]
scala> println("Here is a line with a tabtorttwo, followed byna new line.")
Here is a line with a tab    or    two, followed by
a new line.

scala> println("This will breaks.")
<console>:1: error: invalid escape character
println("This will breaks.")
[/sourcecode]

So, you are supplying a String argument to split, and it uses that to construct a regular expression. Given that s is not a string character, but is a regex metacharacter, you need to escape it. You can of course use split(“””s”””), though that isn’t exactly better in this case.

Q. I have long been programming in C++ and Java. Therefore, I put semicolon at the end of the line unconsciously. It seems that the standard coding style of Scala doesn’t recommend to use semicolons. However, I saw that there are some cases that require semicolons as you showed last class. Is there any specific reason why semicolon loses its role in Scala?

A. The main reason is to improve readability since the semicolon is rarely needed when writing standard code in editors (as opposed to one liners in the REPL). However, when you want to do something in a single line, like handling multiple cases, you need the semicolons.

[sourcecode lang=”scala”]
scala> val foo = List("a",1,"b",2)
foo: List[Any] = List(a, 1, b, 2)

scala> foo.map { case(x: String) => x; case(x: Int) => x.toString }
res5: List[String] = List(a, 1, b, 2)
[/sourcecode]

But, in general, it’s best to just split these cases over multiple lines in any actual code.

Q. Is there no way to use _ in map like methods for collections that consist of pairs? For example, List((1,1),(2,2)).map(e => e._1 + e._2) works, but List((1,1),(2,2)).map(_._1 + _._2) does not work.

A. The scope in which the _ remains unanambigious runs out past its first invocation, so you only get to use it once. It is better anyway to use a case statement that makes it clear what the members of the pairs are.

[sourcecode lang=”scala”]
scala>  List((1,1),(2,2)).map { case(num1, num2) => num1+num2 }
res6: List[Int] = List(2, 4)
[/sourcecode]

Q. I am unsure about the exact meaning of and the difference between “=>” and “->”. They both seem to mean something like “apply X to Y” and I see that each is used in a particular context, but what is the logic behind that?

A. The use of -> simply constructs a Tuple2, as is pretty clear in the following snippet.

[sourcecode lang=”scala”]
scala> val foo = (1,2)
foo: (Int, Int) = (1,2)

scala> val bar = 1->2
bar: (Int, Int) = (1,2)

scala> foo == bar
res11: Boolean = true
[/sourcecode]

Primarily, it is syntactic sugar that provides an intuitive symbol for creating elements of a a Map. Compare the following two ways of declaring the same Map.

[sourcecode lang=”scala”]
scala> Map(("a",1),("b",2))
res9: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 1, b -> 2)

scala> Map("a"->1,"b"->2)
res10: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 1, b -> 2)
[/sourcecode]

The second seems more readable to me.

The use of => indicates that you are defining a function. The basic form is ARGUMENTS => RESULT.

[sourcecode lang=”scala”]
scala> val addOne = (x: Int) => x+1
addOne: Int => Int = <function1>

scala> addOne(2)
res7: Int = 3

scala> val addTwoNumbers = (num1: Int, num2: Int) => num1+num2
addTwoNumbers: (Int, Int) => Int = <function2>

scala> addTwoNumbers(3,5)
res8: Int = 8
[/sourcecode]

Normally, you use it in defining anonymous functions as arguments to functions like map, filter, and such.

Q. Is there a more convenient way of expressing vowels as [AEIOUaeiou] and consonants as [BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz] in RegExes?

A. You can use Strings when defining regexes, so you can have a variable for vowels and one for consonants.

[sourcecode lang=”scala”]
scala> val vowel = "[AEIOUaeiou]"
vowel: java.lang.String = [AEIOUaeiou]

scala> val consonant = "[BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz]"
consonant: java.lang.String = [BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz]

scala> val MyRE = ("("+vowel+")("+consonant+")("+vowel+")").r
MyRE: scala.util.matching.Regex = ([AEIOUaeiou])([BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz])([AEIOUaeiou])

scala> val MyRE(x,y,z) = "aJE"
x: String = a
y: String = J
z: String = E
[/sourcecode]

Q. The “b” in RegExes marks a boundary, right? So, it also captures the “-“. But if I have a single string “sdnfeorgn”, it does NOT capture the boundaries of that, is that correct? And if so, why doesn’t it?

A. Because there are no boundaries in that string!

Intermediate questions

Q. The flatMap function takes lists of lists and merges them to single list. But in the example:

[sourcecode lang=”scala”]
scala> (1 to 10).toList.map(x=>squareOddNumber(x))
res16: List[Option[Int]] = List(Some(1), None, Some(9), None, Some(25), None, Some(49), None, Some(81), None)

scala> (1 to 10).toList.flatMap(x=>squareOddNumber(x))
res17: List[Int] = List(1, 9, 25, 49, 81)
[/sourcecode]

Here it is not list of list but just a list. In this case it expects the list to be Option list.
I tried running the code with function returning just number or None. It showed error. So is there any way to use flatmap without Option lists and just list. For example, List(1, None, 9, None, 25) should be returned as List(1, 9, 25).

A. No, this won’t work because List(1, None, 9, None, 25) mixes Options with Ints.

[sourcecode lang=”scala”]
scala> val mixedup = List(1, None, 9, None, 25)
mixedup: List[Any] = List(1, None, 9, None, 25)
[/sourcecode]

So, you should have your function return an Option which means returning Somes or Nones. Then flatMap will work happily.

One way of think of Options is that they are like Lists with zero or one element, as can be noted by the parallels in the following snippet.

[sourcecode lang=”scala”]
scala> val foo = List(List(1),Nil,List(3),List(6),Nil)
foo: List[List[Int]] = List(List(1), List(), List(3), List(6), List())

scala> foo.flatten
res12: List[Int] = List(1, 3, 6)

scala> val bar = List(Option(1),None,Option(3),Option(6),None)
bar: List[Option[Int]] = List(Some(1), None, Some(3), Some(6), None)

scala> bar.flatten
res13: List[Int] = List(1, 3, 6)
[/sourcecode]

Q. Does scala have generic templates (like C++, Java)? eg. in C++, we can use vector<int>, vector<string> etc. Is that possible in scala? If so, how?

A. Yes, every collection type is parameterized. Notice that each of the following variables is parameterized by the type of the elements they are initialized with.

[sourcecode lang=”scala”]
scala> val foo = List(1,2,3)
foo: List[Int] = List(1, 2, 3)

scala> val bar = List("a","b","c")
bar: List[java.lang.String] = List(a, b, c)

scala> val baz = List(true, false, true)
baz: List[Boolean] = List(true, false, true)
[/sourcecode]

You can create your own parameterized classes straightforwardly.

[sourcecode lang=”scala”]
scala> class Flexible[T] (val data: T)
defined class Flexible

scala> val foo = new Flexible(1)
foo: Flexible[Int] = Flexible@7cd0570e

scala> val bar = new Flexible("a")
bar: Flexible[java.lang.String] = Flexible@31b6956f

scala> val baz = new Flexible(true)
baz: Flexible[Boolean] = Flexible@5b58539f

scala> foo.data
res0: Int = 1

scala> bar.data
res1: java.lang.String = a

scala> baz.data
res2: Boolean = true
[/sourcecode]

Q. How can we easily create, initialize and work with multi-dimensional arrays (and dictionaries)?

A. Use the fill function of the Array object to create them.

[sourcecode lang=”scala”]
scala> Array.fill(2)(1.0)
res8: Array[Double] = Array(1.0, 1.0)

scala> Array.fill(2,3)(1.0)
res9: Array[Array[Double]] = Array(Array(1.0, 1.0, 1.0), Array(1.0, 1.0, 1.0))

scala> Array.fill(2,3,2)(1.0)
res10: Array[Array[Array[Double]]] = Array(Array(Array(1.0, 1.0), Array(1.0, 1.0), Array(1.0, 1.0)), Array(Array(1.0, 1.0), Array(1.0, 1.0), Array(1.0, 1.0)))
[/sourcecode]

Once you have these in hand, you can iterate over them as usual.

[sourcecode lang=”scala”]
scala> val my2d = Array.fill(2,3)(1.0)
my2d: Array[Array[Double]] = Array(Array(1.0, 1.0, 1.0), Array(1.0, 1.0, 1.0))

scala> my2d.map(row => row.map(x=>x+1))
res11: Array[Array[Double]] = Array(Array(2.0, 2.0, 2.0), Array(2.0, 2.0, 2.0))
[/sourcecode]

For dictionaries (Maps), you can use mutable HashMaps to create an empty Map and then add elements to it. For that, see this blog post:

http://bcomposes.wordpress.com/2011/09/19/first-steps-in-scala-for-beginning-programmers-part-8/

Q. Is the apply function similar to constructor in C++, Java? Where will the apply function be practically used? Is it for intialising values of attributes?

A. No, the apply function is like any other function except that it allows you to call it without writing out “apply”. Consider the following class.

[sourcecode lang=”scala”]
class AddX (x: Int) {
def apply(y: Int) = x+y
override def toString = "My number is " + x
}
[/sourcecode]

Here’s how we can use it.

[sourcecode lang=”scala”]
scala> val add1 = new AddX(1)
add1: AddX = My number is 1

scala> add1(4)
res0: Int = 5

scala> add1.apply(4)
res1: Int = 5

scala> add1.toString
res2: java.lang.String = My number is 1
[/sourcecode]

So, the apply method is just (very handy) syntactic sugar that allows you to specify one function as fundamental to a class you have designed (actually, you can have multiple apply methods as long as each one has a unique parameter list). For example, with Lists, the apply method returns the value at the index provided, and for Maps it returns the value associated with the given key.

[sourcecode lang=”scala”]
scala> val foo = List(1,2,3)
foo: List[Int] = List(1, 2, 3)

scala> foo(2)
res3: Int = 3

scala> foo.apply(2)
res4: Int = 3

scala> val bar = Map(1->2,3->4)
bar: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 3 -> 4)

scala> bar(1)
res5: Int = 2

scala> bar.apply(1)
res6: Int = 2
[/sourcecode]

Q. In the SBT tutorial you discuss “Node” and “Value” as being case classes. What is the alternative to a case class?

A. A normal class. Case classes are the special case. They do two things (and more) for you. The first is that you don’t have to use “new” to create a new object. Consider the following otherwise identical classes.

[sourcecode lang=”scala”]
scala> class NotACaseClass (val data: Int)
defined class NotACaseClass

scala> case class IsACaseClass (val data: Int)
defined class IsACaseClass

scala> val foo = new NotACaseClass(4)
foo: NotACaseClass = NotACaseClass@a5c0f8f

scala> val bar = IsACaseClass(4)
bar: IsACaseClass = IsACaseClass(4)
[/sourcecode]

That may seem like a little thing, but it can significantly improve code readability. Consider creating Lists within Lists within Lists if you had to use “new” all the time, for example. This is definitely true for Node and Value, which are used to build trees.

Case classes also support matching, as in the following.

[sourcecode lang=”scala”]
scala> val IsACaseClass(x) = bar
x: Int = 4
[/sourcecode]

A normal class cannot do this.

[sourcecode lang=”scala”]
scala> val NotACaseClass(x) = foo
<console>:13: error: not found: value NotACaseClass
val NotACaseClass(x) = foo
^
<console>:13: error: recursive value x needs type
val NotACaseClass(x) = foo
^
[/sourcecode]

If you mix the case class into a List and map over it, you can match it like you can with other classes, like Lists and Ints. Consider the following heterogeneous List.

[sourcecode lang=”scala”]
scala> val stuff = List(IsACaseClass(3), List(2,3), IsACaseClass(5), 4)
stuff: List[Any] = List(IsACaseClass(3), List(2, 3), IsACaseClass(5), 4)
[/sourcecode]

We can convert this to a List of Ints by processing each element according to its type by matching.

[sourcecode lang=”scala”]
scala> stuff.map { case List(x,y) => x; case IsACaseClass(x) => x; case x: Int => x }
<console>:13: warning: match is not exhaustive!
missing combination              *           Nil             *             *

stuff.map { case List(x,y) => x; case IsACaseClass(x) => x; case x: Int => x }
^

warning: there were 1 unchecked warnings; re-run with -unchecked for details
res10: List[Any] = List(3, 2, 5, 4)
[/sourcecode]

If you don’t want to see the warning in the REPL, add a case for things that don’t match that throws a MatchError.

[sourcecode lang=”scala”]
scala> stuff.map { case List(x,y) => x; case IsACaseClass(x) => x; case x: Int => x; case _ => throw new MatchError }
warning: there were 1 unchecked warnings; re-run with -unchecked for details
res13: List[Any] = List(3, 2, 5, 4)
[/sourcecode]

Better yet, return Options (using None for the unmatched case) and flatMapping instead.

[sourcecode lang=”scala”]
scala> stuff.flatMap { case List(x,y) => Some(x); case IsACaseClass(x) => Some(x); case x: Int => Some(x); case _ => None }
warning: there were 1 unchecked warnings; re-run with -unchecked for details
res14: List[Any] = List(3, 2, 5, 4)
[/sourcecode]

Q. In C++ the default access specifier is private; in Java one needs to specify private or public for each class member where as in Scala the default access specifier for a class is public. What could be the design motivation behind this when one of the purpose of the class is data hiding?

A. The reason is that Scala has a much more refined access specification scheme than Java that makes public the rational choice. See the discussion here:

http://stackoverflow.com/questions/4656698/default-public-access-in-scala

Another key aspecte of this is that the general emphasis in Scala is on using immutable data structures, so there isn’t any danger of someone changing the internal state of your objects if you have designed them in this way. This in turn gets rid of the ridiculous getter and setter methods that breed and multiply in Java programs. See “Why getters and setters are evil” for more discussion:

http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html

After you get used to programming in Scala, the whole getter/setter thing that is so common in Java code is pretty much gag worthy.

In general, it is still a good idea to use private[this] as a modifier to methods and variables whenever they are only needed by an object itself.

Q. How do we define overloaded constructors in Scala?

Q. The way a class is defined in Scala introduced in the tutorial, seems to have only one constructor. Is there any way to provide multiple constructors like Java?

A. You can add additional constructors with this declarations.

[sourcecode lang=”scala”]
class SimpleTriple (x: Int, y: Int, z: String) {
def this (x: Int, z: String) = this(x,0,z)
def this (x: Int, y: Int) = this(x,y,"a")
override def toString = x + ":" + y + ":" + z
}

scala> val foo = new SimpleTriple(1,2,"hello")
foo: SimpleTriple = 1:2:hello

scala> val bar = new SimpleTriple(1,"goodbye")
bar: SimpleTriple = 1:0:goodbye

scala> val baz = new SimpleTriple(1,3)
baz: SimpleTriple = 1:3:a
[/sourcecode]

Notice that you must supply an initial value for every one of the parameters of the class. This contrasts with Java, which allows you to leave some fields uninitialized (and which tends to lead to nasty bugs and bad design).

Note that you can also provide defaults to parameters.

[sourcecode lang=”scala”]
class SimpleTripleWithDefaults (x: Int, y: Int = 0, z: String = "a") {
override def toString = x + ":" + y + ":" + z
}

scala> val foo = new SimpleTripleWithDefaults(1)
foo: SimpleTripleWithDefaults = 1:0:a

scala> val bar = new SimpleTripleWithDefaults(1,2)
bar: SimpleTripleWithDefaults = 1:2:a
[/sourcecode]

However, you can’t omit a middle parameter while specifying the last one.

[sourcecode lang=”scala”]
scala> val foo = new SimpleTripleWithDefaults(1,"xyz")
<console>:12: error: type mismatch;
found   : java.lang.String("xyz")
required: Int
Error occurred in an application involving default arguments.
val foo = new SimpleTripleWithDefaults(1,"xyz")
^
[/sourcecode]

But, you can name the parameters in the initialization if you want to be able to do this.

[sourcecode lang=”scala”]
scala> val foo = new SimpleTripleWithDefaults(1,z="xyz")
foo: SimpleTripleWithDefaults = 1:0:xyz
[/sourcecode]

You then have complete freedom to change the parameters around.

[sourcecode lang=”scala”]
scala> val foo = new SimpleTripleWithDefaults(z="xyz",x=42,y=3)
foo: SimpleTripleWithDefaults = 42:3:xyz
[/sourcecode]

Q. I’m still not clear on the difference between classes and traits.  I guess I see a conceptual difference but I don’t really understand what the functional difference is — how is creating a “trait” different from creating a class with maybe fewer methods associated with it?

A. Yes, they are different. First off, traits are abstract, which means you cannot create any members. Consider the following contrast.

[sourcecode lang=”scala”]
scala> class FooClass
defined class FooClass

scala> trait FooTrait
defined trait FooTrait

scala> val fclass = new FooClass
fclass: FooClass = FooClass@1b499616

scala> val ftrait = new FooTrait
<console>:8: error: trait FooTrait is abstract; cannot be instantiated
val ftrait = new FooTrait
^
[/sourcecode]

You can extend a trait to make a concrete class, however.

[sourcecode lang=”scala”]
scala> class FooTraitExtender extends FooTrait
defined class FooTraitExtender

scala> val ftraitExtender = new FooTraitExtender
ftraitExtender: FooTraitExtender = FooTraitExtender@53d26552
[/sourcecode]

This gets more interesting if the trait has some methods, of course. Here’s a trait, Animal, that declares two abstract methods, makeNoise and doBehavior.

[sourcecode lang=”scala”]
trait Animal {
def makeNoise: String
def doBehavior (other: Animal): String
}
[/sourcecode]

We can extend this trait with new class definitions; each extending class must implement both of these methods (or else be declared abstract).

[sourcecode lang=”scala”]
case class Bear (name: String, defaultBehavior: String = "Regard warily…") extends Animal {
def makeNoise = "ROAR!"
def doBehavior (other: Animal) = other match {
case b: Bear => makeNoise + " I’m " + name + "."
case m: Mouse => "Eat it!"
case _ => defaultBehavior
}
override def toString = name
}

case class Mouse (name: String) extends Animal {
def makeNoise = "Squeak?"
def doBehavior (other: Animal) = other match {
case b: Bear => "Run!!!"
case m: Mouse => makeNoise + " I’m " + name + "."
case _ => "Hide!"
}
override def toString = name
}
[/sourcecode]

Notice that Bear and Mouse have different parameter lists, but both can be Animals because they fully implement the Animal trait. We can now start creating objects of the Bear and Mouse classes and have them interact. We don’t need to use “new” because they are case classes (and this also allowed them to be used in the match statements of the doBehavior methods).

[sourcecode lang=”scala”]
val yogi = Bear("Yogi", "Hello!")
val baloo = Bear("Baloo", "Yawn…")
val grizzly = Bear("Grizzly")
val stuart = Mouse("Stuart")

println(yogi + ": " + yogi.makeNoise)
println(stuart + ": " + stuart.makeNoise)
println("Grizzly to Stuart: " + grizzly.doBehavior(stuart))
[/sourcecode]

We can also create a singleton object that is of the Animal type by using the following declaration.

[sourcecode lang=”scala”]
object John extends Animal {
def makeNoise = "Hullo!"
def doBehavior (other: Animal) = other match {
case b: Bear => "Nice bear… nice bear…"
case _ => makeNoise
}
override def toString = "John"
}
[/sourcecode]

Here, John is an object, not a class. Because this object implements the Animal trait, it successfully extends it and can act as an Animal. This means that a Bear like baloo can interact with John.

[sourcecode lang=”scala”]
println("Baloo to John: " + baloo.doBehavior(John))
[/sourcecode]

The output of the above code when run as a script is the following.

Yogi: ROAR!
Stuart: Squeak?
Grizzly to Stuart: Eat it!
Baloo to John: Yawn…

The closer distinction is between traits and abstract classes. In fact, everything shown above could have been done with Animal as an abstract class rather than as a trait. One difference is that an abstract class can have a constructor while traits cannot. Another key difference between them is that traits can be used to support limited multiple inheritance, as shown in the next question/answer.

Q. Does Scala support multiple inheritance?

A. Yes, via traits with implementations of some methods. Here’s an example, with a trait Clickable that has an abstract (unimplemented) method getMessage, an implemented method click, and a private, reassignable variable numTimesClicked (the latter two show clearly that traits are different from Java interfaces).

[sourcecode lang=”scala”]
trait Clickable {
private var numTimesClicked = 0
def getMessage: String
def click = {
val output = numTimesClicked + ": " + getMessage
numTimesClicked += 1
output
}
}
[/sourcecode]

Now let’s say we have a MessageBearer class (that we may have wanted for entirely different reasons having nothing to do with clicking).

[sourcecode lang=”scala”]
class MessageBearer (val message: String) {
override def toString = message
}
[/sourcecode]

A new class can be now created by extending MessageBearer and “mixing in” the Clickable trait.

[sourcecode lang=”scala”]
class ClickableMessageBearer(message: String) extends MessageBearer(message) with Clickable {
def getMessage = message
}
[/sourcecode]

ClickableMessageBearer now has the abilities of both MessageBearers (which is to be able to retrieve its message) and Clickables.

[sourcecode lang=”scala”]
scala> val cmb1 = new ClickableMessageBearer("I’m number one!")
cmb1: ClickableMessageBearer = I’m number one!

scala> val cmb2 = new ClickableMessageBearer("I’m number two!")
cmb2: ClickableMessageBearer = I’m number two!

scala> cmb1.click
res3: java.lang.String = 0: I’m number one!

scala> cmb1.message
res4: String = I’m number one!

scala> cmb1.click
res5: java.lang.String = 1: I’m number one!

scala> cmb2.click
res6: java.lang.String = 0: I’m number two!

scala> cmb1.click
res7: java.lang.String = 2: I’m number one!

scala> cmb2.click
res8: java.lang.String = 1: I’m number two!
[/sourcecode]

Q. Why are there toString, toInt, and toList functions, but there isn’t a toTuple function?

A. This is a basic question that leads directly to the more advanced topic of implicits. There are a number of reasons behind this. To start with, it is important to realize that there are many types of Tuples, starting with a Tuple with a single element (a Tuple1) up to 22 elements (a Tuple22). Note that when you use (,) to create a tuple, it is implicitly invoking a constructor for the corresponding TupleN of the correct arity.

[sourcecode lang=”scala”]
scala> val b = (1,2,3)
b: (Int, Int, Int) = (1,2,3)

scala> val c = Tuple3(1,2,3)
c: (Int, Int, Int) = (1,2,3)

scala> b==c
res4: Boolean = true
[/sourcecode]

Given this, it is obviously not meaningful to have a function toTuple on Seqs (sequences) that are longer than 22. This means there is no generic way to have, say a List or Array, and then call toTuple on it and expect reliable behavior to happen.

However, if you want this functionality (even though limited by the above constraint of 22 elements max), Scala allows you to “add” methods to existing classes by using implicit definitions. You can find lots of discussions about implicits by search for “scala implicits”. But, here’s an example that shows how it works for this particular case.

[sourcecode lang=”scala”]
val foo = List(1,2)
val bar = List(3,4,5)
val baz = List(6,7,8,9)

foo.toTuple

class TupleAble[X] (elements: Seq[X]) {
def toTuple = elements match {
case Seq(a) => Tuple1(a)
case Seq(a,b) => (a,b)
case Seq(a,b,c) => (a,b,c)
case _ => throw new RuntimeException("Sequence too long to be handled by toTuple: " + elements)
}
}

foo.toTuple

implicit def seqToTuple[X](x: Seq[X]) = new TupleAble(x)

foo.toTuple
bar.toTuple
baz.toTuple
[/sourcecode]

If you put this into the Scala REPL, you’ll see that the first invocation of foo.toTuple gets an error:

[sourcecode lang=”scala”]
scala> foo.toTuple
<console>:9: error: value toTuple is not a member of List[Int]
foo.toTuple
^
[/sourcecode]

Note that class TupleAble takes a Seq in its constructor and then provides the method toTuple, using that Seq. It is able to do so for Seqs with 1, 2 or 3 elements, and above that it throws an exception. (We could of course keeping listing more cases out and go up to 22 element tuples, but this shows the point.)

The second invocation of foo.toTuple still doesn’t work — and that is because foo is a List (a kind of Seq) and there isn’t a toTuple method for Lists. That’s where the implicit function seqToTuple comes in — once it is declared, Scala notes that you are trying to call toTuple on a Seq, notes that there is no such function for Seqs, but sees that there is an implicit conversion from Seqs to TupleAbles via seqToTuple, and then it sees that TupleAble has a toTuple method. Based on that, it compiles and the produces the desired behavior. This is a very handy ability of Scala that can really simplify your code if you use it well and with care.

Copyright 2012 Jason Baldridge

The text of this post is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License. Attribution may be provided by linking to www.jasonbaldridge.com and to this original post.

Suggestions, improvements, extensions and bug fixes welcome — please email Jason at jasonbaldridge@gmail.com or provide a comment to this post.

Variations for computing results from sequences in Scala

Topics: iteration, mapping, for expressions, foreach loops, Lists, ListBuffers, Arrays, indexed sequences, recursion

Introduction

A common question from students who are new to Scala is: What is the difference between using the map function on lists, using for expressions and foreach loops? One of the major sources of confusion with regard to this question is that a for expression in Scala in not the equivalent of for loops in languages like Python and Java — instead, the equivalent of for loops is foreach in Scala. This distinction highlights the importance of understanding what it means to return values versus relying on side-effects to perform certain computations. It also helps reinforce some points about fixed versus reassignable variables and immutable versus mutable data structures.

The task and its functional solution

To demonstrate this, let’s consider a simple task. Given a List of words, compute two lists: one has the lengths of each word and the second indicates whether a word starts with a capital letter or not. For example, start with the following list.

[sourcecode language=”scala”]
scala> val words = List("This", "is", "a", "list", "of", "English", "words", ".")
words: List[java.lang.String] = List(This, is, a, list, of, English, words, .)
[/sourcecode]

We can compute the two lists by mapping over the words list as follows.

[sourcecode language=”scala”]
scala> words.map(_.length)
res0: List[Int] = List(4, 2, 1, 4, 2, 7, 5, 1)

scala> words.map(_(0).isUpper)
res1: List[Boolean] = List(true, false, false, false, false, true, false, false)
[/sourcecode]

So, that’s it. However, let’s do this without using different calls to the map function (or multiple foreach loops, as we’ll see below). The easiest way to do this is to map each word to a tuple containing the length and the Boolean indicating whether its first character is capitalized; this produces a list of tuples, which we unzip to get a tuple of Lists.

[sourcecode language=”scala”]
scala> val (wlengthsMapUnzip, wcapsMapUnzip) =
|   words.map(word => (word.length, word(0).isUpper)).unzip
wlengthsMapUnzip: List[Int] = List(4, 2, 1, 4, 2, 7, 5, 1)
wcapsMapUnzip: List[Boolean] = List(true, false, false, false, false, true, false, false)
[/sourcecode]

The key thing here is that the map function turns the List[String] words into a List[(Int, Boolean)] — which is to say it returns a value. We can assign that value to a variable, or use it immediately by calling unzip on it, which in turn returns a value that is a Tuple2(List[Int],List[Boolean]).

Before moving on let’s define a simple function to display the results of performing this computation, which we will do in various ways (and which all produce precisely the same results).

[sourcecode language=”scala”]
def display (intro: String, wlengths: List[Int], wcaps: List[Boolean]) {
println(intro)
println("Lengths: " + wlengths.mkString(" "))
println("Caps: " + wcaps.mkString(" "))
println
}
[/sourcecode]

Calling this function with the result of mapping and unzipping as above, we get the following output.

[sourcecode language=”scala”]
scala> display("Using map and unzip.", wlengthsMapUnzip, wcapsMapUnzip)
Using map and unzip.
Lengths: 4 2 1 4 2 7 5 1
Caps: true false false false false true false false
[/sourcecode]

Okay, so now let’s start doing it the hard way. Rather than mapping over the original list, we’ll loop over the list with foreach, and perform a side-effect computation that builds up the two result sequences. This is the sort of thing that is typically done in non-functional languages with for loops, hence the use of foreach in Scala. We’ll explore each of these in turn.

The second variation: use reassignable, immutable Lists

We can use reassignable variables which are initialized to be empty Lists, and then prepend to them as we loop through the words list. We are thus using a variable that has the type of List, which is an immutable sequence data structure, but its value is being reassigned each time we pass through the loop.

[sourcecode language=”scala”]
var wlengthsReassign = List[Int]()
var wcapsReassign = List[Boolean]()
words.foreach { word =>
wlengthsReassign = word.length :: wlengthsReassign
wcapsReassign = word(0).isUpper :: wcapsReassign
}

display("Using reassignable lists.", wlengthsReassign.reverse, wcapsReassign.reverse)
[/sourcecode]

Note that we build up the lists by prepending, which means they come out of the loop in reverse order and thus must be reversed before being displayed. You can of course append to a List by creating a singleton List and concatenating the two Lists with the ::: operator.

[sourcecode language=”scala”]
scala> val foo = List(4,2)
foo: List[Int] = List(4, 2)

scala> foo ::: List(7)
res0: List[Int] = List(4, 2, 7)
[/sourcecode]

However, this is not recommended because it is computationally costly. Adding an element to the front (left) of a List is a constant time operation, whereas concatenating two lists requires time proportional to the length of the first list. That might not seem like a big deal until you are dealing with lists with thousands of elements, and then you’ll find that the same bit of code that prepends many times and then reverses is much faster than one which appends using the above strategy.

Third variation: use unreassignable, mutable (growable) ListBuffers

Next, we can use a ListBuffer, which is a mutable sequence data structure that also happens to support constant time append operations. We can thus declare it as a val, and then use the method append to mutate the sequence so that it has a new element at the end. So, the variables referring to the sequences are not reassignable, but their values are mutable.

[sourcecode language=”scala”]
import collection.mutable.ListBuffer
val wlengthsBuffer = ListBuffer[Int]()
val wcapsBuffer = ListBuffer[Boolean]()
words.foreach { word =>
wlengthsBuffer.append(word.length)
wcapsBuffer.append(word(0).isUpper)
}

display("Using mutable ListBuffer.", wlengthsBuffer.toList, wcapsBuffer.toList)
[/sourcecode]

Note that we must convert the ListBuffers to Lists for the call to display in order to have the right types as arguments to that function.

Since they can efficiently grow (i.e., get longer), ListBuffers are a good choice for many problems where we need to accumulate a set of results, and especially when we don’t know how many results we will be accumulating. However, if you know the number of results you’ll be accumulating it’s probably better to use Arrays, as shown next.

Fourth variation: use unreassignable, mutable (but fixed length) Arrays

Both of the above alternatives probably look a little strange to people coming from Java. In Java, you’d be more likely to do an imperative solution that involves initializing arrays that have the same length as words and then filling in respective indices as appropriate. To do this, use Array.fill(lengthOfArray)(initialValue).

[sourcecode language=”scala”]
val wlengthsArray = Array.fill(words.length)(0)
val wcapsArray = Array.fill(words.length)(false)
words.indices.foreach { index =>
wlengthsArray(index) = words(index).length
wcapsArray(index) = words(index)(0).isUpper
}

display("Using iteration and arrays.", wlengthsArray.toList, wcapsArray.toList)
[/sourcecode]

We go through the indices and for each one compute the value and assign it to the appropriate index in the corresponding Array. Again, we need to convert the results to Lists before calling display. The indices method does exactly what you’d expect — it gives you the indices of the List.

[sourcecode language=”scala”]
scala> words.indices
res2: scala.collection.immutable.Range = Range(0, 1, 2, 3, 4, 5, 6, 7)
[/sourcecode]

A problem with the above foreach loop is that it requires indexing into Lists, which is generally a bad idea. Why? Because to get the i-th item from a list requires time proportional to i operations. Why? Because the implementation for obtaining an item at a particular index i involves peeling off the head of the list to get its tail, and then seeking for the i-1-th item of the tail, which requires peeling off its head and then seeking for the i-2-th item, and so on. So, if you want to get the 10000th item in a list, you have to perform 10,000 operations to get it. If the words list had 10,000 elements, you can now see that you’d perform 10,000 basic computations just on the foreach, and for each element you do 2*index operations to get the word at that index, which means doing 20,000 operations on the last index alone.

Note that indexing into Arrays is a constant time operation, so there is no problem with the left hand side of the assignments in the above loop.

You might think you can do better by first storing the word and then using it twice, e.g.

[sourcecode language=”scala”]
words.indices.foreach { index =>
val word = words(index)
wlengthsArray(index) = word.length
wcapsArray(index) = word(0).isUpper
}
[/sourcecode]

This is better, but it only saves us half the operations. Since we were perfectly happy to loop over the words themselves before, we actually shouldn’t have to do this look up — we can do better by having a reassignable counter index that allows us to set values to the correct positions in the new Arrays we are creating.

[sourcecode language=”scala”]
val wlengthsArray2 = Array.fill(words.length)(0)
val wcapsArray2 = Array.fill(words.length)(false)
var index = 0
words.foreach { word =>
wlengthsArray2(index) = word.length
wcapsArray2(index) = word(0).isUpper
index += 1
}
[/sourcecode]

Since this sort of pattern is fairly common, Scala provides a handy method on sequences called zipWithIndex which returns a List of the original elements paired with their indices.

[sourcecode language=”scala”]
scala> words.zipWithIndex
res3: List[(java.lang.String, Int)] = List((This,0), (is,1), (a,2), (list,3), (of,4), (English,5), (words,6), (.,7))
[/sourcecode]

In this way, we can have the foreach loop over such pairs. It is convenient in these cases to use the pattern matching abilities in foreach loops by using the case match on pairs, as below.

[sourcecode language=”scala”]
val wlengthsArray3 = Array.fill(words.length)(0)
val wcapsArray3 = Array.fill(words.length)(false)
words.zipWithIndex.foreach { case(word,index) =>
wlengthsArray3(index) = word.length
wcapsArray3(index) = word(0).isUpper
}
[/sourcecode]

It’s important to understand the cost of the operations you are using, especially in looping contexts where you are inherently doing the same basic operation multiple times.

Indexed sequences (Vectors)

It is worth pointing out that when you want an immutable sequence that allows efficient indexing, you should use Vectors.

[sourcecode language=”scala”]
scala> val bar = Vector(1,2,3)
bar: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3)
[/sourcecode]

If you have a List in hand but want to index into it repeatedly, you can convert it to a Vector using toIndexedSeq.

[sourcecode language=”scala”]
scala> val numbers = List(4,9,9,2,3,8)
numbers: List[Int] = List(4, 9, 9, 2, 3, 8)

scala> numbers.toIndexedSeq
res5: scala.collection.immutable.IndexedSeq[Int] = Vector(4, 9, 9, 2, 3, 8)
[/sourcecode]

IndexedSeq is a supertype of sequences which are designed to be efficient for indexing, and Vector is the default “backing” implementation when you call toIndexedSeq on a List.

Of course, if you are only ever going over all the elements of a sequence in order, then Lists are likely to be preferable since they have a bit less overhead and they have some nice properties for pattern matching in match statements.

Using predefined funtions for mapping over a sequence

Another thing worth pointing out is that if you have a predefined function, you can pass that as the argument to map, which can lead to very concise code for this task. Assume you have defined a function that takes a String and produces a Tuple of its argument’s length and whether it starts with an upper-case letter.

[sourcecode language=”scala”]
def getLengthAndUpper = (word: String) => (word.length, word(0).isUpper)
[/sourcecode]

The code for mapping over words with this function to get our desired lists is then very clean.

[sourcecode language=”scala”]
val (wlengthsFunction, wcapsFunction) = words.map(getLengthAndUpper).unzip
[/sourcecode]

Of course, you would probably only do this if you needed that same function in other places. If not, it’s preferable to just use the anonymous function like in the first map example in this blog post. However, you can see that if you have a library of simple functions like this, you can now start writing much clearer and simpler code by reusing them when mapping over different lists.

For expressions

Notice that the previous loops were all foreach ones, whereas Java programmers and Pythonistas will be used to for loops. Scala doesn’t have for loops — it has for expressions. A common question then is: What’s the difference? What is a for expression for and why isn’t it a for loop? The difference is that an expression returns a value, so while foreach allows you to plow through a sequence and do some operation to each element, a for expression allows you to return a value for each element. Consider the following, in which we yield the square of each integer in a List[Int].

[sourcecode language=”scala”]
scala> val numbers = List(4,9,9,2,3,8)
numbers: List[Int] = List(4, 9, 9, 2, 3, 8)

scala> for (num <- numbers) yield num*num
res6: List[Int] = List(16, 81, 81, 4, 9, 64)
[/sourcecode]

We get a result, whereas a foreach loop just does the computation and returns nothing.

[sourcecode language=”scala”]
scala> numbers.foreach { num => num * num }
[/sourcecode]

The key is that we yield a value for each element in the for expression. In this case, it is basically equivalent to using map. Here it is in the context of the running words example.

[sourcecode language=”scala”]
val (wlengthsFor, wcapsFor) =
(for (word <- words) yield (word.length, word(0).isUpper)).unzip

display("Using a for expression.", wlengthsFor, wcapsFor)
[/sourcecode]

Having said all this, it turns out you can use a for expression as a loop, without returning any values, e.g. as follows.

[sourcecode language=”scala”]
scala> for (num <- numbers) { println(num*num) }
16
81
81
4
9
64
[/sourcecode]

I think it is generally better to use a foreach loop for such cases so that it is clear that you are only performing side-effects, like printing, reassigning the values of var variables, or modifying mutable data structures. However, there are some cases where a for expression can be more convenient, for example when working through multiple lists and doing various filtering operations. Here’s a quick example to give a flavor of this. Given two lists, we can enumerate the cross product of all their elements

[sourcecode language=”scala”]
scala> val numbers = List(4,9,9,2,3,8)
numbers: List[Int] = List(4, 9, 9, 2, 3, 8)

scala> val letters = List(‘a’,’C’,’f’,’d’,’z’)
letters: List[Char] = List(a, C, f, d, z)

scala> for (n <- numbers; l <- letters) print("(" + n + "," + l + ") ")
(4,a) (4,C) (4,f) (4,d) (4,z) (9,a) (9,C) (9,f) (9,d) (9,z) (9,a) (9,C) (9,f) (9,d) (9,z) (2,a) (2,C) (2,f) (2,d) (2,z) (3,a) (3,C) (3,f) (3,d) (3,z) (8,a) (8,C) (8,f) (8,d) (8,z)
[/sourcecode]

You can filter on these values as well to restrict the output to just some reduced set of elements of inter(est.

[sourcecode language=”scala”]
scala> for (n <- numbers; if (n>4); l <- letters) print("(" + n + "," + l + ") ")
(9,a) (9,C) (9,f) (9,d) (9,z) (9,a) (9,C) (9,f) (9,d) (9,z) (8,a) (8,C) (8,f) (8,d) (8,z)
[/sourcecode]

There is much more to this, but I’ll leave it here since using for expressions in this way is a rich enough topic for several blog posts in and of itself. Also, there is a detailed discussion of it in Odersky, Spoon, and Venner’s book “Programming in Scala.”

Fifth variation: use a recursive function

It’s worth pointing out one other way of building up lengths and caps lists. Recursive functions are functions which look at their input and then either return a result for a base case or compute a result and then call themself with that result. It’s pretty standard stuff that computer scientists love and which tends to get used a lot more in functional programming than in imperative programming. Here, I’ll show how to do the same task done before using recursion, but without an in-depth explanation, so either you’ll already know how to do recursion and you can see it in Scala for the same problem context as above, or you don’t know much about recursion but can use this as an example of how it is employed for a task you already understand from the vantages given above. So, in the later case, hopefully it will be useful in conjunction with other tutorials on recursion.

First, we need to define the recursive function, given below. It has three parameters: one for the list of words, one for the already computed lengths and another for the already computed caps. It returns a pair that has first the list of lengths with one additional item prepended to it and then the list of caps values with one additional item prepended to it. The items being prepended are computed from the head of the inputWords list.

[sourcecode language=”scala”]
def lengthCapRecursive(
inputWords: List[String],
lengths: List[Int],
caps: List[Boolean]): (List[Int], List[Boolean]) = inputWords match {

case Nil =>
(lengths, caps)
case head :: tail =>
lengthCapRecursive(tail, head.length :: lengths, head(0).isUpper :: caps)
}
[/sourcecode]

We can call this function directly, but it is often convenient to provide a secondary function that makes the initial call to this function with empty result lists as the second and third parameters. The secondary function can then perform the reversal and return the desired computed lists.

[sourcecode language=”scala”]
def lengthCapRecursive(inputWords: List[String]): (List[Int], List[Boolean]) = {
val (l,c) = lengthCapRecursive(words, List[Int](), List[Boolean]())
(l.reverse, c.reverse)
}
[/sourcecode]

Getting the result is then just a matter of calling that function with our words list.

[sourcecode language=”scala”]
val (wlengthsRecursive, wcapsRecursive) = lengthCapRecursive(words)

display("Using a recursive function.", wlengthsRecursive, wcapsRecursive)
[/sourcecode]

A slight variation on this that is slightly cleaner is to “hide” the recursive function inside the secondary function, which then effectively acts as a wrapper to the recursive function. This is often considered cleaner because the programmer can ensure that the initialization is done correctly and that the recursive function itself isn’t given malformed inputs.

[sourcecode language=”scala”]
def lengthCapRecurWrap(inputWords: List[String]): (List[Int], List[Boolean]) = {

// This function is hidden from code that doesn’t
def lengthCapRecurHelp(
inputWords: List[String],
lengths: List[Int],
caps: List[Boolean]): (List[Int], List[Boolean]) = inputWords match {

case Nil =>
(lengths, caps)
case head :: tail =>
lengthCapRecurHelp(tail, head.length :: lengths, head(0).isUpper :: caps)
}

val (l,c) = lengthCapRecurHelp(words, List[Int](), List[Boolean]())
(l.reverse, c.reverse)

}

val (wlengthsRecurWrap, wcapsRecurWrap) = lengthCapRecurWrap(words)

display("Using a recursive function contained in a wrapper.", wlengthsRecurWrap, wcapsRecurWrap)
[/sourcecode]

Conclusion

So, that provides an overview of different ways of obtaining the same results and some explanation of the different properties of each solution in terms of computational considerations that are likely to crop up in your code and you should be aware of.

Clearly there are many ways of getting the same thing done in Scala. This can be hard for newcomers to the language since they don’t have good intuitions about which approach is better in different circumstances, but it is quite valuable to have these options as you become more savvy and understand what the costs and benefits of using different data structures and different ways of iterating are.

All of the code from the above snippets are gathered together in the Github gist ListComputations.scala. You can save it as a file and run it as “scala ListComputations.scala”  to see the output and play around with modifications to the code.