Week 4: Scala
I'm now past the half-way point of Seven Languages in Seven Weeks. This week was about the language Scala. Due to time constraints and interest level, I haven't given it quite as much attention as some of the other languages the book has looked at so far.
Week 1 ˙ Week 2 ˙ Week 3 ˙ Week 4 ˙ Week 5 ˙ Week 6 ˙ Week 7
Here is how Bruce Tate introduces Scala:
It's a hybrid language, meaning that it intentionally tries to bridge the gaps between programming paradigms. In this case, the bridge is between object-oriented languages like Java and functional languages like Haskell.
Its placement in the middle chapter of Seven Languages in Seven Weeks seems very deliberate. Scala is a language that works with object-oriented and functional paradigms. I've gotten some exposure to object-oriented concepts in the chapters on Ruby and Io. The remaining chapters in the book are about functional languages: Erlang, Clojure, and Haskell. My main goal from this chapter was to reinforce some object-oriented concepts and get an introduction to some functional ones, so I didn't mind skipping over a few things (like concurrency) to save time.
Scala ran slower on my netbook than the other languages so far have. I think that's because it compiles everything to the Java Virtual Machine (JVM) before running it.
Here are some useful methods from Scala along with my other notes from the chapter:
- Strings, integers, lists, etc. are all objects in Scala. Like in Ruby, you can append
.methodname
to an object to run a method on it. - Every object has to have a type (e.g.
String, Int, Double, Float, List, Set, Map, Boolean
). Scala will infer the type from context where possible.+
adds numbers but concatenates strings, so trying to add objects of different types may work (if they haven't been explicitly declared) but produce an unexpected result. - Variables can be declared with
val variablename: Type = ...
. Type can be omitted if it can be inferred. Variables set up in this way cannot be changed: they are immutable. To initialize variables that can modified (i.e. mutable), replaceval
withvar
. The statement+=1
iterates a mutable variable by one. - If you write a script (which can be run from the command line with
scala script.scala argument(s)
) then the objectargs
can be used in the script to reference the arguments passed to it.args(0)
gives the first argument andargs.length
gives the number of arguments. - The syntax for
if, while, for
is pretty normal. - Here are some ways data can be structured:
- Ranges:
(start to end)
or(start until end)
(the former includes the endpoint); addby step
to use a step size other than 1..start
and.end
methods return the first or last value, respectively. - Tuples: Have a fixed length and go in parentheses. They can be used for multi-value assignment, such as
val (x,y) = (1,2)
. Usetuplename._1
to get the first value. - Lists: Create a list with
List(contents)
. Access the first value withlistname(0)
. Useful methods to use on lists include:.isEmpty, .length, .size, .head, .tail, .last, .init, .reverse, .drop(n)
..tail
and.init
return all but the first or last element, respectively. - Sets: Sets are like a list except the order doesn't matter. You can add or subtract single elements from a list using
+
or-
and do set union/difference/intersection with++, --, &
operators. - Maps: Contain key-value pairs (like a hash in Ruby or a map in Io). Create one with
Map(key -> value, ...)
.
- Ranges:
- I liked Io because it had some object-oriented features without needing to deal with classes. Classes in Scala seem similar to Ruby. You can use the keywords
extends
andoverride
when one class inherits from another. Atrait
is a container for a single method. It can be added to a class using the keywordwith
. - To define a function, the syntax is:
def functionname(parameter: Type, ...):Type = statement
. I think the type of each parameter needs to be stated but the type of data the function returns can be left empty and Scala will infer what it should be. .foreach
is the "iteration workhorse" according to Bruce Tate. It takes a code block (in parentheses on the same line or between curly braces if spread over multiple lines) as an argument. The code block can contain an anonymous function (parameter(s) => statement
) to act on each element passed from a list.- Other methods that can be called on a list and take an anonymous function (to run on each element) as a parameter include
.count, .map, .filter, .forall, .exists, .sortWith, .foldLeft
. The final one is powerful; an example is shown below. - One really impressive feature of Scala is that XML is a built-in type and can be conveniently manipulated.
.text
will strip out the tags,\ "name"
finds nodes of the given name and\ "@attribute"
gives the values in the corresponding attribute field. I've shown an example below.
Here are some examples of Scala:
One of the examples in Seven Languages in Seven Weeks was to create a class
called Compass that knows how to turn left and right around the cardinal directions. Here is a screenshot (from gedit) because I think this one is easier to follow with some syntax highlighting:
In this example, directions is a list containing the cardinal directions. bearing is a mutable (declared with var
) variable that serves as its index. direction() is a function with no argument that simply returns the element from directions at the current bearing. inform() is a function that takes a single parameter (the string "left" or "right") and prints a statement saying what way it is turning and what direction it is facing. It uses +
to concatenate some strings. turnRight() and turnLeft() are functions with no parameters. They update the bearing (the index for directions), using the modulus operator (%
) to wrap around directions instead of going out of range. At the bottom of the script, a new
object is created from the Compass class and the .turnRight
and .turnLeft
methods are called.
I mentioned above that the .foldLeft
method is quite powerful. In honour of Pi Day, I wrote this method to calculate pi by alternately adding and subtracting reciprocals of odd numbers (the Madhava-Leibniz-Gregory method):
def mlgPi(n:Int):Double = {
(1 to n).foldLeft(1.0)((piByFour, term) => piByFour + (1.0 - (2.0 * (term.toDouble % 2.0)))/(2.0 * term.toDouble + 1.0))
}
val result = mlgPi(1000) * 4.0
println(result)
This function takes an integer as an argument (the number of terms to include in the series). It creates a range to get the requested number of terms then uses the .foldLeft
method to do the calculation. The initial value (1.0) is given then an anonymous function based on the result so far (piByFour) and the current element of the range (term). The modulus operator is used to alternate between +1 / -1 which is then divided by an odd number calculated from the current element of the range. I found it kind of tough to do math in Scala because of the way it infers object types. The math operators were looking for Int
or Double
types while I was trying to use Float
types. Eventually I made everything a Double
and got it working.
I really liked the ease of using xml in Scala. I tried the examples in the book on some simplified/contrived kml (kml uses the same structure as xml, just different tags); I've played with kml quite a bit before, so I could really see the potential usefulness here:
scala> val places =
| <Placemark id="one">
| <name>Place One</name>
| <coordinates>-66,45,0</coordinates>
| </Placemark>
places: scala.xml.Elem =
<Placemark id="one">
<name>Place One</name>
<coordinates>-66,45,0</coordinates>
</Placemark>
scala> places.text
res0: String =
"
Place One
-66,45,0
"
scala> places \ "coordinates"
res1: scala.xml.NodeSeq = NodeSeq(<coordinates>-66,45,0</coordinates>)
scala> places \ "@id"
res2: scala.xml.NodeSeq = one
scala> :quit
places is an xml object. Calling .text
on it strips away the tags. places \ "coordinates"
shows the node(s) with the <coordinates>
tag. places \ "@id"
shows the contents of the id=
attribute.
I didn't look for any links for further reading on Scala.
I'm finding it very helpful to see the same concepts/paradigm in multiple languages. After seeing some object-oriented concepts in Ruby, Io, and now Scala I feel like I'm getting a better understanding overall. Classes and code blocks in Scala took less time to pick up on than in Ruby and I don't think that's because the language is simpler. As I look ahead to the final half of the book (functional languages Erlang, Clojure, and Haskell), I'm hoping that the bridge provided by Scala will kickstart the same process of understanding in the Functional paradigm.