Pages

04 July 2007

Scala to heaven, first step

Now let's start with our first step with Scala.

In the next posts, I'll be certainly assuming that you come to Scala from Java, however everybody is welcome!

I want first to demonstrate the use of a wonderful idea, borrowed from Haskell, the Option class. And this will be used with pattern matching. Said like that, this looks like advanced Computer Science stuff, but it's not.

This will help us manage something that plagues a lot of java applications: the dreaded NullPointerException.

An Option to parse options

Yes, I admit it. Parsing "options" on a command line is not the better way to introduce the "Option" class. So I'll try to go slow enough to reduce the confusion I have introduced in the first place,...

Anyway, this is a "real" example ("real" as "I'm using it", not as "the space shuttle runs with that"). I wrote a small utility in Scala to analyse the options passed on a command line. It can be used that way:

val action = getOptionValue("-action", "generateQuotes", args)


where
  • "-action" is the name of the option on the command line: -action generateQuotes for instance
  • generateQuotes is the default action if no "-action" option has been specified
  • args is an array of string containing all the options passed on the command line (typically through the main static method)
The Java way

How can I implement this getOptionValue method? Let's first provide a parseOption function taking only the name of the option and the arguments (args) as parameters. This function should return the value of the option if such a thing exists on the command line. What could be a Java implementation of that?

public String getOptionValue(String name, String defaultValue, Array[String] args) {
final String option = parseOption(name, args);
if (option == null)
return defaultValue;
else
return option;
}

public String parseOption(String name, Array[String] args) {
for (int i=0; i < args.length - 1; i++)
if (args[i].equalsIgnoreCase(name) && i < args.length - 1 && args[i+1] != null)
return args[i+1];
return null;
}

Please don't stare too much at the for loop, it is very naive but it was as YAGNI as I needed. Let's focus instead on the return value of the parseOption function. This function can either return a String or a null pointer meaning "I have not found an option value corresponding to the name you were asking for".

Unfortunately, if I don't look at the parseOption code, I have no way to tell what the return value when the option is not found. Is it null, is it an empty string? Many times, in real life, this can be pretty much hard to tell, because the value comes from another function which comes from,... and so on.

So in presence of a large codebase, you may eventually add a superflous check:

if (option == null || option.equals("")) return defaultValue;

Better be safe than sorry,...

The Scala way

Now what does Scala offers in that situation?

The Option class provides 2 subclasses:
  • None, which represents "I have found nothing"
  • Some, which represents "I have found something, and you can get it"
The parseOption function in Scala is defined like this:

def parseOption(name:String, args:Array[String]): Option[String] = {
for (i <- List.range(0, args.length - 1))
if (args(i).equalsIgnoreCase(name) && i < args.length -1 && args(i+1) != null)
return Some(args(i+1))
return None
}



And the getOptionValue function is defined with:
def getOptionValue(name:String, defaultValue:String, args:Array[String]): String = {
parseOption(name, args) match {
case None => defaultValue
case Some(value) => value
}
}


which reads like:
  1. parse the option with the name 'name'
  2. if you find nothing, return the defaultValue
  3. if you find some(thing), designated by 'value', return that value
Pattern matching in 3 sentences

In Scala, the "object match {case xxx => ...}" construct implements the "pattern matching" idea. Given an object, if its "structure" matches a given pattern, you can use parts of this object to do your job. In that case, I get an object 'Some', which was constructed from a 'value', so I can de-construct the object and access the value.

The death of the NPE?

I find this in itself quite useful and elegant, but this is not all! What if you forgot to add a None clause to your match construct? You get a compiler warning! So, not only you can infer from the parseOption signature that you will have to deal with None values, but you are even reminded to do so!

Now, if you add the Option class to the fact that Scala encourages you to declare final variables (with the "val" modifier, a bit shorter that "final" in Java) and forces you to assign a value to modifiable ones, you can really think twice when you have to write the word "null" in a Scala program.

And even more to the point

And there are other jewels, too. You can convey this idea of a "defaultValue" in an even more concise way. The Option class has a "getOrElse" method, so the code above can be rewritten as:

def getOptionValue(name:String, defaultValue:String, args:Array[String]) = {
parseOption(name, args).getOrElse(defaultValue)
}


You can also do it the other way around. You can define an action that will be done only if the value exists. The Option class implements Iterable, so you can write:

parseOption(name, args).foreach(Console.println _)

In that example foreach iterates on every value contained in the Option (designated by "_") and print it. So the value is printed only if it exists. Of course, here, I would really prefer a more meaningful term (such as "do") but you know what? There is also a technique that allow you to add methods to scala library classes, so it is possible to write that too! More on that later,...

References

To the interested reader, here are some more references:
  • This is how David Pollak uses options, in the lift web framework, written in Scala
  • The ancestor: Maybe in Haskell (you will also notice the presence of an Either structure which can be very convenient too)

Never ending debate

As a conclusion I will add another layer at the dynamic typing vs static typing debate. One of the goal I follow by using Scala is to experiment when and how static typing is better than dynamic typing. My current observations are:
  • Sometimes it can be irritating to get the types right, and you have to be quite aware about things such as co-variance, contra-variance, dependent types and all the folklore. I will certainly write a post about that to give another "real-life" example, otherwise it can look pretty esoteric. The way I see it is that static typing is a way to encode some business constraints so that they can be checked before you even run the program. Sometimes it is possible and clean, sometimes the translation from your domain constraints to type constraints is a bit clumsy but it works, sometimes it is downright impossible and you need some "programming"
  • There are some things I can do with dynamic typing that I can not do with static typing, such as generating some classes with repetitive attributes and methods, depending on the content of a file. The dynamic solution is very concise and provide "just good enough" objects
Longer post than I thought for a "first step" but I really hope this will give you some drive to try Scala out and then you'll get the virus!

03 July 2007

Scala to heaven, ground

Selecting one "Programming language of the year", yes but which one?

The contenders

I pre-selected several contenders:

1. An ML language, such as OCaml
2. A "purely" functional language such as Haskell
3. A language designed for concurrency such as Erlang

Those 3 languages looked very interesting to me, each of them addressing fundamental software considerations. Well that's the rational pitch. But what was anedoctically exciting?

Observation round

Erlang was the promise to venture in a domain where I feel seriously weak, concurrent programming, with a brand new paradigm, very different from what I know. OCaml was a bit unknown to me, the only references I had were a colleague telling me that he gave up with OCaml one day the type inferencer was as lost as him and a financial company actually using it.

Haskell was perhaps the most appealing, for 2 reasons: QuickCheck (I loved Tom's Moertel description of his participation to IFCP) and the promise of mind-bending ideas baked in the language.

In order to shed more light on the subject I started reading.

"A history of Haskell, being lazy with class", is a wonderful way to introduce the language and give great insights on the "why" more than the "what" and "how". I also read "The little MLer" to become more familiar to the ML kind. And I was waiting for Joe Armstrong's book on Erlang.

But then I noticed something. Yes, that little language, there, hidden behind the others, come here!

I have a winner

What's your name? Scala
What do you know about concurrent programming? I, I have a clever actors library which may help get those performances
What about functional programming? Well, I unify the object and function approaches so you can get best of both worlds
How useful are you? I can play well with your existing java infrastructure
Do you do pattern matching and gadt? Yep
Isn't static typing to tiring? No, you just have to declare the bare minimum. The rest is inferred. By the way, this should allow me to get a top-level IDE with refactoring and code completion soon.
What about some cool stuff I have in Haskell? You mean Options, Parsers/Combinators and QuickCheck? Can do that too.
Are you system-engineering friendly? Some even pretend that dependency injection is part of me
Can you ease XML processing? I have XML literals and pattern matching against xml structures
Can I write DSLs with you? I am not Ruby but I have clever tricks that can help you a lot for that.

And the list goes on. I haven't discovered the least of what can be done with Scala and it is funny to see on the mailing list that even the language designers seems to think that there will be unexpected and surprising uses of scala features in the future.

First steps

The next steps in the "Scala to heaven" series will try to demonstrate the use of day-to-day Scala features to solve my own programming issues. As a beginner, I feel this is missing. We have good examples in the documentation, but abundance of examples won't be bad.