Today marked my progress through chapters 2, 3, and a small part of 4 (more on that next time; it’s about stuff I largely already know but adds some of Scala’s own twist to classes and the likes). So far, the biggest hurdle is the syntax. It’s like a strange mix between Java, Python, and even a little BASIC (because of the array indices). I can certainly feel the influences other languages have had on Scala already!
The unusual thing is that I’m starting to catch on to the more fundamental principle behind functional languages: Functions should have no side effects. Really, it makes far more sense. When performing a replace operation on a string, for example, the original object should not be modified; instead, a new object is returned with the replacements applied and the original object remains untouched.
It is no surprise then that Scala includes data structures that fall into two categories: mutable and immutable. Near as I can gather at this point, the former is intended for imperative-style writing while the latter is preferred for functional. But, that’s simply where the fascinating bits start. Let’s take a look at tuples.
The Tuple
Like Python (and a few other languages), Scala has a tuple construct that provides an array-like immutable data structure that can be used as keys, key/value pairs, and so forth. The biggest difference, as I can tell, is that Scala tuples aren’t exactly like Python tuples; you can’t use array-like indices to reference a tuple offset. Instead, it appears that you really need to know the structure of the tuple ahead of time. Mind you, that’s not a big deal as Scala provides many other data structures that could be used as a Python tuple might.
You can build things with tuples, but let’s explore objects
I’m really excited about some of the things I’ve learned related to tuples. For the sake of clarity, however, I really need to discuss one of the more interesting things I learned related to objects in Scala. As such, I hope that you’ll forgive me for the brief digression. I have a lot of things to cover, so backtracking is sometimes a necessary evil!
Speaking of backtracking, I suspect this post will work roughly like our memories. To illustrate, think of a time when you were walking along a sidewalk on a beautiful day. Beams of sunlight were streaming between the trees as the shadows of birds scaled their way up the hill before you. The birds almost immediately enter your field of view and then you encounter an incredibly perfume floating about on the air. You turn and notice a handful of flowers sprouting among the bushes to your left, and then you remember a particular chore you still had to take care of–such as delivering flowers to your girlfriend, mother, or what have you.
Then a neighborhood dog barks and instantly shatters the serenity of this landscape into a million pieces. The birds are a distant memory, the fragrance of flowers have been blown away on the brisk morning air, and the only thing in your mind is a vague sense of frustration. That damned dog ruined it all.
Next, some random idiot comes careening passed you on his bicycle–nearly hitting you. You spit in anger briefly as the rush of air blows by. You notice that a magazine in his book back flies out across the sidewalk and blows onto the road. Glancing at the rolled up paper briefly, you wonder if the approaching car is fated to hit it. You smirk wryly, maybe even consider what a joy karma is in moments like these, and then the vehicle swerves away from the magazine. That moron on the bike apparently noticed that his bag had come loose and sent a few of his things flying into the air like a swarm of stirred up bees. He sheepishly walks his bike passed you.
As you glance at the man, you start to think back on what that chore was you so wished you could remember. Birds? Maybe it was chicken. No, wait, we fixed chicken for dinner last night. Hmmm…
And then you think about it for a few minutes more. You even consider for a moment the prospect of retracing your steps from earlier in the morning. Those flowers smelled so wonderful… EUREKA!
Then it hits you.
That’s sort of what the purpose of my backtracking is. It serves to both jog my memory as well as grant me an excuse to make up a story to share.
The world of objects in Scala
Scala, like Python, is what I would call a “pure” object-oriented programming language. Everything is an object. Operations call methods on each object (including integers). However, unlike Python, there are no true operations. +, -, /, and * are all individual methods; in Python, the + operator calls the object’s __add__
method whereas in Scala, there exists a method called, quite literally, +. That’s it. Thus, in Scala, addition can be written in two ways:
// Addition using "standard" syntax: var added = 1 + 2 // Addition using method calls: var added = (1).+(2) // ...which could also be written as: var added = 1.+(2) |
Isn’t that interesting? What’s more, every single operator in Scala is a method. This works because methods in Scala that except a single argument can be written without parenthesis. Therefore, the standard 1 + 2
operation works as well.
Let’s talk again about loops
Now, I really do want to get back to tuples. They excited me. First, I need to illustrate further this notion of “everything as an object” (or method). Remember how in my first post, I discussed the .foreach()
method of looping through an array? Guess what? There’s another way to do it using the range method. Here’s an example:
val sometext = Array("This", "is", "an", "example!") for (i <- 0 to sometext.length-1) { println(blargh(i)) } |
This prints:
This is an example!
As in addition, this translates into two things. First, the <-
operator can be read as “in.” I’m not sure if this is an actual method that is created or whether this is a genuine Scala operator. I imagine this will come clear in a few chapters. Second, the part that reads 0 to sometext.length-1
creates a range between the values of 0 and sometext.length
minus one. This could also be written as: (0).to(sometext.length - 1)
. Or, if you really wanted additional verbosity: (0).to(sometext.length.-(1))
.
So what’s this got to do with tuples?
Well, nothing much, really. (I’ll explain shortly.) Tuples, as I mentioned earlier, are simple data structures. Here’s an example of a tuple containing multiple data types as well as Scala’s output (I’m using the command line interpreter):
scala> val tup = (1, "one") tup: (Int, java.lang.String) = (1,one) |
Notice that Scala creates a tuple object containing the data types Int
and java.lang.String
(all data types in the JVM-version of Scala are just Java data types with some wrappers). This is handy; it’s also important to know that there exists another method: ->
. Here’s the ->
method at work:
scala> var tup = 1 -> "one" tup: (Int, java.lang.String) = (1,one) |
Notice that the ->
operator created a tuple? Remember, too, that there is another way to write this:
scala> (1).->("one") res41: (Int, java.lang.String) = (1,one) |
(Don’t use 1.->("one")
or it’ll use a Double instead of an Int.)
Here’s why this is important.
Maps use tuples. True story!
To create a Map
or a HashMap
in Scala, you might do something like the following:
scala> var numbers = Map[Int, String]() numbers: scala.collection.immutable.Map[Int,String] = Map() scala> numbers += 1 -> "one" scala> numbers += 2 -> "two" scala> numbers += 3 -> "three" scala> numbers res4: scala.collection.immutable.Map[Int,String] = Map(1 -> one, 2 -> two, 3 -> three) |
See how I used the ->
operator here? That’s because maps use tuples to “map” values internally. More importantly, the +=
operator is just a method; by default, this method will create a new map containing both the existing values and the new value (the default maps are immutable). However, if you were to type this before any of the example code (above), import scala.collection.mutable.Map
, you’d wind up with a mutable version of Map
in which +=
appends a new item to the map. Thus, here’s what the code above might look like when we’re adding new items to the map:
numbers.+=((1).->"one") |
Which could also be written as:
numbers.+=((1, "one")) |
And if you’re really adventurous, you could also write this to avoid having to give the compiler hints about the data types (that’s the cruft in square brackets):
var numbers = Map((1, "one"), (2 -> "two"), (3).->("three")) |
That’ll cover nearly all bases! Isn’t it amazing?
A thought to leave
I’ll leave you with some thoughts for this evening. I’m very impressed with Scala so far. The syntax is a little difficult to learn for anyone coming from an imperative programming background, but the shear expressive power of Scala is dumbfounding. I’m incredibly excited by the language already, and I haven’t even touched but a small fragment of code in Programming in Scala. What’s strange is that it hasn’t been as difficult to pick up as I imagined. While I’ve run into errors, naturally, while playing around in the interactive interpreter, the errors I have created for myself are few and far between. I can’t wait to get into the Actors model of multiprocessing. I think that’s where Scala is going to truly shine. Plus, I’m intending to try it out by writing an MD5-sum generator of files on a file system (that seems to be my generic “Hello, world!” application of choice–strange!).
Anyway, I may not have another entry in this section for a couple of days. The weekend is coming up, and I have to cook for the folks as they have some guests stopping by. I’ll try an squeeze in another one on Sunday if I can’t make it Saturday. Oh, and I’ve decided that I might just skip Links of the Week this week. I know some of you really enjoy that section, so I’ll try and get something for you!