Slides From My Presentation on Operator Overloading In Scala

Last night I spoke at the Atlanta Scala Enthusiats meeting about operator overloading and a little on implicit conversions. I think the talk went well as I got lots of really good questions from the audience, and they laughed at my jokes. This presentation grew out of a blog post I wrote a few months ago entitled Scala Gets Operator Overloading Right; I beefed it up and made some slides and more code samples. Incidentally, if you Google for “scala operator overloading” that blog post is the first result.

For those of you who weren’t there, here are my slides and the code samples that go with them. I wrote these samples against Scala 2.7.7.final. They should work with the latest Scala 2.8, but I haven’t verified this.

And here’s the source code: oopres.zip

What the Heck Is a Tuple, Anyway?

Yesterday I was talking with a friend about Scala and the subject of tuples came up. We both had a bit of a laugh that neither of us was sure how to pronounce it, though we both leaned toward TUH-ple instead of TOO-ple. Anyway, the utility of tuples in Scala was not immediately apparent to him, so I thought I’d take a whack at explaining it here.

A Tuple in Scala is an immutable container used for storing two or more objects, possibly of different types. While a List or Array can only store objects that all have the same type, Tuples can store objects of any type. The most common use of tuples is when you have a method that needs to return more than one value, but creating a class for that return value is more trouble than it’s worth. It’s true that for same-type objects you could return a List, and for different-type objects you could return a List[Any], but both of these have downsides, which we’ll discuss.

Let’s look at a very contrived example. Let’s say you created a function that takes a string and returns the starting index of the first numbers if finds and the numbers themselves. That code might look like this

def reFind(str: String) = {
	val re = """(d+)""".r

	val m = re findFirstMatchIn str

	m match {
		case Some(m) => (m.start, str.substring(m.start, m.end))
		case None => (0, "")
	}
}

(I’ve removed any error checking for brevity.) You can see here that we’re creating a regular expression that looks for one or more numbers grouped together. We then match that against the passed-in string. The matching method returns a Some[Match], so we pattern match against that to see if we actually got a match. If we did, we create a tuple with the starting index of the match, and the match itself, and return it. If not, we return a tuple with 0 for the starting index and an empty string.

Calling this function looks like this

scala> val t = reFind("foo 123 bar")
t: (Int, java.lang.String) = (4,123)

You can see that what was returned is something with type (Int, java.lang.String); that’s actually an instance of Scala’s Tuple2 class. (There’s a synonym for Tuple2, called Pair.)

Now that we have this tuple, what do we do with it? If you want to access the values it contains, you do it in a way that might seem a bit strange at first. To get at the elements, you could do this

scala> val i = t._1
i: Int = 4

scala> val m = t._2
m: java.lang.String = 123

There are two things to point out here. First, unlike Lists and Arrays, you don’t use the () notation. You use a method consisting of an underscore and the index of the part you want. Second, unlike Lists and Arrays, tuples are 1-based instead of 0-based. (According to Programming In Scala, this is a nod to Haskell and ML.) Also notice the types of the vals you are assigning. That’s one of the benefits of using a Tuple instead of something like List[Any]; you still get compile-time type safety. Had you instead written the function like this

def reFind(str: String) = {
	val re = """(d+)""".r

	val m = re findFirstMatchIn str

	m match {
		case Some(m) => List[Any](m.start, str.substring(m.start, m.end))
		case None => List[Any](0, "")
	}
}

and called it, look what happens when you try to store the Int index in a local variable

scala> val l = reFind("foo 123 bar")
l: List[Any] = List(4, 123)

scala> val i: Int = l(0)
<console>:10: error: type mismatch;
 found   : Any
 required: Int
       val i: Int = l(0)
                    ^

You would get a similar error trying to assign the String element to a local String val. That’s the major downside to using a List[Any]. (In the first example I used Scala’s type inference to set the types of the local variables; this time I wanted to be explicit to show the failure.)

As I mentioned earlier, you could define a class just to handle the return values of this function. There is nothing wrong with that solution, and some will find it superior to using a tuple, because you can assign meaningful names to the elements. You could define it like this

class ReResult(val index: Int, val part: String)

def reFind(str: String) = {
	val re = """(d+)""".r

	val m = re findFirstMatchIn str

	m match {
		case Some(m) => new ReResult(m.start, str.substring(m.start, m.end))
		case None => new ReResult(0, "")
	}
}

and call it like this

scala> val l = reFind("foo 123 bar")
l: ReResult = ReResult@57c52e72

scala> val i: Int = l.index
i: Int = 4

scala> val m: String = l.part
m: String = 123

If you think this is more maintainable, then by all means, use it. If you just want to easily return more than one value from a function, then consider using a tuple.

Another point on tuples is that you can assign all the elements of a tuple to local variables in a single step, rather than using multiple calls. So this is equivalent to all the assignments from the earlier examples

scala> val (i: Int, m: String) = l
i: Int = 4
m: String = 123

Depending on what you’re doing, this could be a useful way to get at the elements.

And one more thing. There are tuple classes that range from two elements all the way up to twenty-two. The classes are named Tuple2, Tuple3 … Tuple22. The () notation for creating tuples applies all the way up to twenty-two arguments, so you rarely need to actually use the class names. For example,

scala> val t = (23, "foo", 18.0)
t: (Int, java.lang.String, Double) = (23,foo,18.0)

scala> t.getClass
res31: java.lang.Class[_] = class scala.Tuple3

scala> val t1 = ('a', "quick", 23, "year-old", """foxy""".r, List(1, 2, 3))
t1: (Char, java.lang.String, Int, java.lang.String, scala.util.matching.Regex, List[Int]) = (a,quick,23,year-old,foxy,List(1, 2, 3))

scala> t1.getClass
res32: java.lang.Class[_] = class scala.Tuple6

I’m not going to provide an example of creating a Tuple22; that is left as an exercise. 🙂 I would argue that if you need more than three elements, you really should define a class to hold them. I think that beyond three elements it gets difficult to keep them straight. Tuples are great for holding two or three pieces of information, but don’t go crazy with them.

Real Southern Cooking. Oh, Yes.

Friday we made one of our few yearly adventures into that most fearsome of places, the city of Atlanta. We live about 30 miles outside the city, but we only venture in a few times a year. This time, it was to visit the Georgia Aquarium and the World of Coca-Cola.

As we were planning the trip, we decided to have dinner at Mary Mac’s Tea Room. This place has been an Atlanta institution since 1945. I’ve known about it all my life, but strangely enough, I’ve never eaten there. Tammy had just seen a piece about it on some food show on TV, so I suggested we go there, since we were going to pass it on the way to the Aquarium. She agreed, and we did.

After dining there, I really wish we had not waited so long to go. This was, quite possibly, the best not-cooked-at-home Southern food I’ve ever had. The first thing they bring you is a basket of bread. Hot homemade yeast rolls, delicious cornbread and sweet & sticky cinnamon rolls, with real butter to slather on them. Oh my. Since it was New Year’s Day, they were giving everyone a little dish of black-eyed peas, because eating those on NYD is supposed to bring good luck. I love black-eyed peas, and these were delicious.

For my meal, I had the country fried steak, fries and spiced apples. I was expecting a piece of cubed steak, with a heavy, fried chicken-like crust, and a white gravy. What I got was like what my mother-in-law makes; three pieces of cubed steak, lightly dredged in flour and fried, smothered in a heavenly brown gravy. It was so amazingly good. I was a bit disappointed in the fries; I was expecting either steak fries or hand-cut fries, but what I got was straight from a bag. The apples were OK, but needed more sugar. These deficiencies were more than made up for by the deliciousness of the steak.

Tammy had chicken & dumplings, macaroni & cheese and collards. I don’t normally like chicken & dumplings, but I had several bites of hers. I would order those again, that’s how good they were. The mac & cheese, again, tasted like homemade; a thick, rich cheese smothering the macaroni, with just a hint of hot pepper sauce. Nothing like the Kraft “cheese and macaroni.” I also tried the collards. I don’t like collards, but these were the best I’ve ever tasted.

Thomas got a burger. It was a huge, hand-made burger that was one of the best I’ve ever tasted. I had the leftovers the next day. 🙂

Then came desert. Thomas had a scoop of chocolate ice cream and Tammy and I both had the banana pudding. Oh yes, the banana pudding. Its deliciousness is almost beyond words. This was not vanilla Jell-O pudding with banana slices and vanilla wafers. This was real banana pudding, with loads of banana slices in it, a heavy bread base and a light meringue  on top. Yeah, it was awesome.

The place is a little pricey, so it can’t be a regular dining experience for us. But I hope to go there at least a few more times this year. 🙂 It will at least become a once-a-year thing for us.