Sunday, September 27, 2009

Scala: Beyond Hello World

I overheard someone at work last week asking another guy how he would go about implementing string-wrapping in Java. Memories came flooding back of university functional programming assignments where we had to use Miranda to shape nursery rhymes into a trapezoid.

I listened to the continuing conversation and realised that the solution being discussed - which involved seeking through the string, remembering where the last whitespace was and cutting off substrings at appropriate points - was obviously imperative in nature. "Not that there's anything wrong with that." If I wasn't reading a book about Scala programming at the moment I would have joined right in. But my functionally-leaning mind instantly started to wonder what the functional solution would be.

It sounded like a simple but interesting problem to try and solve with a new language - a nice "real" program to attempt after Hello World. So I sat down after work and whipped up a small Scala program to wrap words. I have to admit, it took a bit longer than I expected - over an hour. Though a large part of that was spent looking up docs for the List class and trying to solve new and bemusing syntax errors, I do recall getting distracted by an investigation into when tail call optimisation does and doesn't occur.

If you're new to Scala and looking for a little problem to help you learn some syntax and waste an hour, I can recommend word-wrapping as a suitable foe. My solution is below. If you come up with your own, I'd love to know what you did differently!


object Wrapper {

type Line = List[String]

def main(args: Array[String]) {
for (i <- 1 to 31) print(if (i == 31) '\n' else '.')
val s = "This is a really, really long line of text that, hopefully, " +
"will be long enough to sufficiently test a function that must " +
"divide a really, really long string into lines that are no " +
"more than 30 (that's thirty) characters long."
for (line <- wrap(s)) {
for (string <- line) {
print(string + " ")
}
println
}
}

def wrap(stringToWrap : String) : List[Line] =
wrap(List.fromArray(stringToWrap.split(" ")), 30, List(List()))

def wrap(stringsToWrap : List[String],
maxLineLength : Int,
lines : List[Line]) : List[Line] =
stringsToWrap match {
case Nil => lines.reverse
case nextString :: remainingStrings =>
if (lineLength(lines.head) + nextString.length <= maxLineLength)
wrap(remainingStrings, maxLineLength,
(lines.head ::: List(nextString)) :: lines.tail)
else {
wrap(remainingStrings, maxLineLength, List(nextString) :: lines)

}
}

def lineLength(s : Line) : Int = s match {
case Nil => 0
case head :: tail => 1 + head.length + lineLength(tail)
}

}

Sunday, September 20, 2009

Missing Parameter Type For Expanded Function?

I just made a silly Scala syntax mistake and got a fairly unhelpful compiler error message (often the case with newer languages). Google wasn't much help, so I thought I should post up the solution to help others save time in the future.

The code I wrote was essentially this:

def main(args: Array[String]) {
println(for {s <- List("One", "Two", "Three")} yield _) }

And the error I got was this:

error: missing parameter type for expanded function ((x$1) => List("One", "Two", "Three").map(((s) => x$1)))
println(for {s <- List("One", "Two", "Three")} yield _)

My novice mistake was in assuming that I could use an underscore to access the variable from the 'for' comprehension. Simply changing that underscore to 's' fixed it good:

def main(args: Array[String]) {
println(for {s <- List("One", "Two", "Three")} yield s) }

Something else worth noting is that the command-line scalac was actually much more helpful than my IDE, because it printed a third line with a caret pointing straight at the underscore, while the IDE only told me what line the error was on.

Thursday, September 17, 2009

Hey Scala, Where's My Ternary Operator?

While still playing around with Scala Hello World programs, I thought I'd do a little Java integration test so I wrote this awesome program:
println(Math.random() > 0.5 ? "Hello World!" : "Goodbye World")

The result, of course, was neither "Hello World!" nor "Goodbye World" (lest this be a very short blog), but...
error: identifier expected but string literal found

Huh? Why wouldn't that work? Is there no ternary operator? How primitive!

Of course, it dawned on me without too much more wasted neurons: this is a functional language - everything returns a value! (It has been some time, but the memories are slowly starting to come back.) So, of course, it only makes sense that if/else returns a value as well. Voila:

println(if (java.lang.Math.random() > 0.5) "Hello World!"
else "Goodbye World")

And once you see it, you see how obvious it is - that this is just the way if/else should work. Why should any language need a quirky ternary operator when they all have a perfectly good if/else construct already?

On a related note, I'm feeling an increasing annoyance as I look at Java code at work all day. For example, today I was looking at code that essentially did this:

public List convert(List customers) {
ArrayList dtos = new ArrayList();
for (Customer c : customers) {
dtos.add(convert(c));
}
return dtos;
}

public CustomerDTO convert(Customer c) {
return new CustomerDTO(c.getCustomerId(), c.getName(), c.getBalance());
}


So, as soon as I saw that, I thought, "Man, if we were using Scala, I'd just have to write this:"
def convert(customers : List[Customer]) =
customers.map(c => new CustomerDTO(c.customerId, c.name, c.balance))

In fact, the expression is so short, you most likely wouldn't even bother to put it in a function. (Except to test it, or mock it.)

The brevity here isn't just "cool" (even though it is). This is an extremely simple piece of code; and an extremely common operation. The brevity of the Scala code helps to express how simple the function is, whereas the Java code for the same operation takes longer to read and could leave you wondering whether there was something you missed.

The most ridiculous thing about this comparison is that Java has been around for almost 15 years now! And still we have to write 5 lines of code to do ridiculously simple operations like this. I can't imagine it would be much work at all for a few smart guys to add the functionality that Scala displays here to Java, but it appears more and more that Java is slowing to a halt under its own sheer weight and the burden of keeping 6 million-odd developers happy. (As if writing the above code over and over again is the way to do it.)

R.I.P. Java?

Saturday, September 12, 2009

New to Scala? Study the Syntax. CAREFULLY.

So, it only took me about five seconds to go from having a Hello World Scala program working to having a 10% more complex Hello World program failing in a way that I had no idea how to fix.

Here's my program:

object HelloWorld {
def main(args: Array[String]) {
println(testfunc)
}

def testfunc() {
"Hello World!"
}
}

and the output of this awesome program? Just this...
()


If you're a seasoned Scala programmer, you can probably see already why I'm such an idiot, but there's an important point to be made here.

I was trying to test out two things with this example. First, this being the first time I've done functional programming in almost ten years, I wanted to "practice" the idea that the last expression in a function is the return value. Yes, I wanted to practice not writing "return". Secondly, I had read that Scala let's you invoke functions without parentheses, so I thought I'd give that a go by calling "testfunc" instead of "testfunc()".

But neither of these were the problem here. The problem was that, during all my Java-ingrained, time-poor reading of Scala tutorials, I'd had seen but never cared to take particular notice of one small Scala detail: function declarations and function definitions are separated by an equal sign:


object HelloWorld {
def main(args: Array[String]) {
println(testfunc)
}

def testfunc() = {
"Hello World!"
}
}

This code produces the output I was expecting at first: that magic phrase "Hello World!"

I'm actually really glad this happened. It wasted ten minutes of my time, but it taught me a real lesson that I've forgotten through not learning new languages often enough: sit at the computer and type the examples in. No amount of reading examples will actually make you understand a language or teach you how to write it. Only by sitting down, typing in every symbol from an example and understanding what it does (and figuring out where you stuffed it up) can you hope to become proficient.

There is a corollary lesson here, too: no matter how much people tell you Scala is like Java and how much you want to believe it, Scala is NOT Java. There are little differences which, as in this example, can make a HUGE difference. My approach from here on in will be to try and forget about "migrating" my knowledge from Java (the language) to Scala, and just approach Scala as an absolutely new language that needs learning from scratch.

Lastly: The thing that got me really confused is that my original code, complete with the nonsensical error, compiled and ran! To be honest, I still have absolutely no idea what that code is actually doing. If I change my 'println(testfunc)' to 'println(testfunc.getClass)', the output is:
class scala.Predef$$anon$1
So, I'm guessing that my function definition without the equal sign is somehow defining an anonymous type rather than a function, but I really am guessing - I actually have no idea. I'm looking forward to burying my head more and more into Scala syntax until one day I finally gain the knowledge to understand my mistake and jump up screaming "Aha!"

UPDATE:
Well, it only took a little more reading to discover what the original code is doing. Despite Scala being a primarily functional language, it still has the concept of "procedures", or what would be void methods in Java. These are methods that don't return a value, and they are defined using the exact same syntax as a function, except without the equal sign.

So, my original assumption - that my function was not being invoked but was instead being passed to println as some kind of anonymous type - was quite wrong. The function IS being invoked, but it doesn't return anything. But why does the code compile and run if the method returns nothing? That's because everything in Scala has a value. Even procedures that don't return anything still have a value! Crazy. (But fun.)

Friday, September 11, 2009

My First Scala Issue

Decided to try writing some Scala before going to a talk on it at my local JUG. That way I could put my hand up with the cool group when they ask "Who's actually written some Scala?".

scala-lang suggested that any of Eclipse, IDEA or NetBeans have mature plugins, so I downloaded IntelliJ IDEA 9.0M1, installed the plugin, pasted in someone else's Hello World example, hit CTRL-SHIFT-F10 and then sat back to watch in awe.

Unfortunately, there was no Scala joy. IDEA was kind enough to tell me that "Compilation completed with 1 error and 0 warnings" but wouldn't show me anything about what the error actually was. The line above was simple followed by a pretty little red 'X' icon, with no text next to it.

I Googled around a bit and found a few people - but not many - had had a similar problem. Maybe it was a Snow Leopard issue? Some JetBrains guys had suggested to someone else that the character encoding of their scala files mightn't be what Scala was expecting. So I spent half an hour trying to play around with the character encodings of my single file, my whole project and the compiler, but got nowhere.

In the end, I found a simple solution: I deleted IDEA 9.0M1, downloaded IDEA 8.1 and started again. Within 3 minutes the HelloWorld was compiled and running, with no sign of invisible errors. Hooray!

Lesson learned: Maybe it's better not to try and experiment with a fast-moving, non-core technology (e.g. Scala) in a pre-GA Java IDE release (IDEA 9.0M1).