Thursday, August 17, 2006

Scala might be Java platform's new hope

Last saturday was rainy, and I spent a big part of saturday's afternoon reading "Scala by Example". I was, and am still, rather blown away.

As many other fellow professionals working with Java on a daily basis and having it pay our bills, I'm somewhat dissatisfied with the language, especially seeing the innovation going on in the C# language. C# acquired lots of interesting traits in its 2.0 and upcoming 3.0 release, and let me list some of them here without striving for completeness:


  • Anonymous functions, and even

  • lambda expressions

  • type inference, so instead of "String x = new String()" you can write "var x = new String()"

  • related to type inference, it now has anonymous types, which is a very nice feature for i.e. adding strong typing to a results of a SQL projection

  • generator functions, using the "yield" keyword. This allows certain quite useful forms of continuation-passing programming techniques incl. coroutines without it looking much like continuation passing at all, much like in Python.



And I could go on. Now, there's little hope for Java to achieve this, however there's Scala - a language built on top of JVM, its compiler producing Java .class files that interface seamlessly with any other Java code, and supports a bunch of the above features.

One of quite mind-blowing aspects of the language is its support of generic types. You can explicitly require nonvariance, covariance or contravariance for type parameters and the generic types will act accordingly. I.e. a Stack[String] by default is not a subclass of Stack[AnyRef] by virtue of String being a subclass of AnyRef, but it can be, if Stack[T] is defined to be covariant in the T type parameter. Scala even has a type named "Nothing" that is the bottom element of the subclass relation lattice, a subtype of all types. You can declare the empty stack to be of type "Stack[Nothing]", and have it be compatible with any other stack type without annoying compiler warnings. Contrast this with Collections.EMPTY_SET in JDK 1.5.

There's some real innovation going on in the area of libraries in the C# world. Things that come to mind are LINQ and CCR. Both of them heavily leverage the new syntactic aspects of C#. It occurred to me that if one were to "port" these libraries to JVM, one should probably do it in Scala, and not in Java. In Java, you'd end up with lots of explicit interface declarations and anonymous inner classes, that have quite a syntactic baggage, i.e. compare the verbosity of

filter(x => x * x)

with


filter(new LambdaExpression()
public float calculate(float x) {
return x * x;
}));


Rather straightforward, isn't it? Also, I realized that Scala's for-comprehensions basically already implement the basic LINQ. You can write expressions like:

for (val p <- persons; p.age > 20) yield p.name

To obtain a list of names of persons older than 20 years. LINQ does the same basically for in-memory objects. In Scala, a for comprehension works on any kind of a collection that appropriately implements the "map", "flatMap", and "filter" methods. Built-in lists, streams, and arrays all do, which is quite a good start. Unfortunately, this is something that can't be easily extended to relational data sources, at least not until Scala allows the argument to "filter" to take a parsed abstract syntactic tree of a lambda expression instead of a function object with the compiled bytecode for the said expression. C# people had to resort to a trick here with their DLINQ implementation - they now have the C# compiler emit a representation of the AST for a lambda expression if the type of the variable it is assigned to is a special "System.Expressions.Expression" type. That way, the DLINQ can analyze the lambda expression and convert it into a SQL query. As I said, Scala doesn't have this feature - yet. Being free of standardization lock-in and of legacy baggage, it could soon gain this feature as well.

As I said, if you work with Java, consider whether Scala could fit your next project. You needn't give up any of your Java infrastructure and libraries, as Scala compiles to bytecode, and you gain the expressivity and productivity that a fully featured functional language plus a big pile of accompanying syntactic sugar can give you.

2 comments:

Chris Double said...

Scala also seems to be nice and easy to extend. They have libraries for an erlang like lightweight threading and messaging model that integrates nicely with the language. Have a look at how 'futures' and 'promises' get added as a library:

http://www.bluishcoder.co.nz/2006/07/scala-futures-and-lazy-evaluation.html

Attila Szegedi said...

Yep, thanks for pointing it out, even if I'm aware of it already (I'm tracking your blog's newsfeed :-) ).

Just yesterday I was re-reading some tutorials on the E language, where promises are a central language feature, used to guarantee that execution is never blocking (and thus threads never deadlocking), and was thinking about bringing it to Scala with the full semantic they have in E. In E, a thread doesn't block on a not-yet-fulfilled promise, but rather you attach a block of code to it using the "when" keyword that'll execute when it gets fulfilled. The variable scope for that block of code is local to the method, similar to how Java anonymous inner classes work. It would require some additional runtime support to implement in Scala though - to execute all "when" blocks declared when the promise is fulfilled, potentially in parallel, something akin to Microsoft's Concurrency and Coordination Runtime, and we'd need a nice way to syntactically declare "eventual sends", but it's all no doubt doable. Actually, the feature set of MS CCR would be really great to have in Scala. If I had enough spare time, I'd undertake it myself.