Sunday, December 30, 2007

Scala: first impressions

I'm reading the prerelease of the Scala book, since I'm working for a heavily Java-invested organization now and programming in Java feels like running a race with cement shoes. Politically, Jython doesn't seem like an option; Scala might be an easier sell.

Here's some of my impressions going through the book.

Scala is a decent scripting language

[updated this section thanks to comments from anonymous, Jörn, and Eric.]

Here's how you can loop through each line in a file: Python:

import sys
for line in open(sys.argv[0]):
   print line
Scala:
import scala.io.Source
Source.fromFile(args(0)).getLines.foreach(println)

The scala interpreter also has a REPL, which is nice for experimenting.

This article has more examples of basic scripting in scala.

Getters and setters

One thing I despise in Java is the huge amount of wasted lines of code dedicated to getFoo and setFoo methods. Sure, your IDE can autogenerate these for you, but it still takes up lines in your editor and effort to mentally block them out when examining an unfamiliar class to determine what it does.

C# has Python-style properties, so in theory could be virtually free of this kind of boilerplate, since there is no syntactic difference between "foo.x = y" whether x is a raw field or a property. So, the right thing to do, which you'll see in Python code, is using a raw public field until you actually need extra logic, at which point you replace it with a property and nobody's code breaks.

But C# wasn't far enough removed from Java culturally so everyone writes boilerplate properties instead of boilerplate getters and setters. (I'm aware that in a compiled language like C# it makes sense to start with properties for classes in certain kinds of libraries but these make up a vanishingly small number of actual classes in the wild.)

This is a long way of saying that Scala's properties make a lot of sense given the audience they are targetting (Java programmers). Scala vars are automatically turned into properties (or getters and setters, if you prefer to think in terms of those). So even the most obstinate fan of boilerplate code has absolutely no reason to keep writing unnecessary getters and setters.

If you need to manually tweak your properties later, you can magically define a setter for "field" by naming a method "field_=". This seems a bit like a one-off hack rather than part of a well-designed system, but I can live with it. (Since parentheses are optional for a scala method taking no arguments, any no-argument method call is already syntactically indistiguishable from a raw field read.)

Scala doesn't know what it wants to be when it grows up, yet

Scala contains a lot of features from a lot of different influences, which means there's often competing styles to use; the young scala community hasn't yet decided which to emphasize. For instance, iteration vs traversal -- "for (item <- items)" vs "items.foreach" -- or even whether to leave out optional (inferred) type declarations.

Perhaps this is merely a failure of one book trying too hard to make scala be all things to all readers.

Random thoughts

  • Scala needs something like Python's enumerate function; if you want to loop each object in a collection but you need its index too, you have to do a manual for loop.
  • Using parenthesis for collection access ("array(0); map("foo"))") makes it unnecessarily difficult to tell if you're looking at a method call or a collection access.
  • The scala stdlib is not very google-able yet; if you don't know exactly the class you are looking for ahead of time, you probably won't find it. For example, when looking for a scala object that could iterate through lines in a file, I correctly guessed the scala.io package, but would never have bothered looking at Source until more googling turned it up in a blog entry.

Conclusion and disclaimer

This is long enough; I'll probably write more as I go through more of the book. Patterns and implicit conversions are particularly interesting.

I was attracted to scala while looking for a sane alternative to Java on the JVM and it looks like scala might "drag Java programmers halfway to Python," to paraphrase Guy Steele. And I'm happy to be corrected on anything I've written here.

21 comments:

Wilkes Joiner said...

"drag Java programmers halfway to Python" which only pulls them 3/4ths of the way to lisp ;)

Laurent Szyster said...

To get the convenience of Python
in a JVM without Jython, use
Rhino's JavaScript.

No other JVM scripting solution has the of the set of features that Rhino offers and none has a longer track record.

Also, JavaScript syntax is close enough to Java. So prototyping in JavaScript to deliver in Java can be profitable.

Kevin Dangoor said...

I've been watching Scala for a time as an "interesting language", but I'm beginning to agree with Laurent: JavaScript may prove to be a big winner on the JVM yet. Particularly with ECMAScript 4.

JT Olds said...

Have you seen Groovy? I would suppose you have, but potentially worth a look if not.

I'm pretty excited about ECMAScript 4.

Anonymous said...

Well, you should loose the boilerplate to make the comparision fair:

io.Source.fromFile("foo.out").getLines.foreach(println)

is enough code.

Jonathan Ellis said...

Not so; scalac complains "error: expected class or object definition"

I explained in the article why I'm counting code required to make a reusable program, not just code to experiment in the REPL.

Joe said...

In relation to the C# properties, whilst there is no syntactic difference, the compiled dll's are unfortunately different and not interchangeable.

This means that if you want the flexibility of changing your behaviour in the future, you are forced to insert all the get and set noise into your code.

Jörn Zaefferer said...

A slightly different approach to the file IO example:

import scala.io.Source._
object fileio extends Application {
fromFile("foo.out").getLines.foreach(print)
}

Using foreach(print) instead of foreach(println) gives me a better result. Though again an example where Scala hasn't quite settled on one approach for a common problem.

I'm using the Scala Eclipse plugin which compiles the file on save, hiding the extra compile step from me. I agree that its hardly a "true" scripting language without that tool.

About the enumerate method: Yeah, I was missing that, too. Good thing with Scala is that you've got good chances to ask for that an actualy see it in one of the next releases, which isn't too far away. And until then you can just add it yourself with implicit.

With posts like yours odds are quite good that Google will have more to find in the future.

Jonathan Ellis said...

joe: that's why I said "it makes sense to start with properties for classes in certain kinds of libraries," specifically libraries for use by others. For libraries and other code for internal use only, that is, the vast majority of code, who cares if you have to recompile; you do it constantly anyway. :)

jorn: thanks for the comment; I hope the eclipse plugin stabilizes soon.

Jörn Zaefferer said...

About scala as scripting language: Did you actually try to run a "script" on the command-line via "scala myscript.scala"? I've just tested it with a file that just contained println("Hello, world") and it works just fine. No need to provide an application object or a main method.

Jonathan Ellis said...

Ah... I totally missed that part. Duh. Thanks for hitting me over the head with it. :)

Jonathan Ellis said...

I started editing the post to explain that scala was really a decent language for short scripts after all, but couldn't figure out a way to read command-line arguments without a main method and scalac, so I ended up making only minor changes. Am I missing the obvious still? :)

Eric said...

Hi Jonathan,

You can try that:

scala hello.scala "arg1" "arg2"

with hello.scala:

println("hello")
args foreach {s:String => println(s)}

This will print:

hello
arg1
arg2

Is that what you're looking for?

Eric.

Jonathan Ellis said...

Thanks, Eric. Updated one last (?) time.

Eric said...

I'm glad that Scala gets the popularity it deserves!

I'm really a Scala fan (being tired of Java as pretty much everyone else). Yet I haven't used it much for pure scripting stuff (only when scripting involves using existing java libraries). In that case I feel much more comfortable with Ruby.
Anyway your post is interesting and I would like to know how far we can push Scala to become a "total" scripting language.

> So even the most obstinate fan of boilerplate code has absolutely no reason to keep writing unnecessary getters and setters
You can also refer to case classes where you also have equality, hashcode and pattern matching for free.

>Scala needs something like Python's enumerate function; if you want to loop each object in a collection but you need its index too, you have to do a manual for loop.
You have the method List.zipWithIndex which can help you

>Using parenthesis for collection access ("array(0); map("foo"))") makes it unnecessarily difficult to tell if you're looking at a method call or a collection access.
This is indeed a method, the "apply" one (page 55 in the book)

What I would really like to have for 2008 is lightweight script environment with autocompletion (with a less than 2s startup time,...). I don't know how feasible this is but this would make Scala a very, very interesting scripting language over the dynamic ones.

Eric.

PS: "advertising" -> if you're interested, you can have a look to my scala project (http://code.google.com/p/specs). I'm very interested in getting as much as possible (constructive ;-)) feedback about it.

jaydonnell said...

Hey jonathan, you commented on my blog about scala.io.Source and I see you're using it here. There is a small problem with it, it loads the entire file in memory. The code in my file was used to process some large files which caused an out of memory exception if I used scala.io.Source.

@eric
I can't wait to try out specs, I'm a long time rubyist and a heavy user of rspec. Thanks for making specs :)

John said...

I'm a newbie at scala too. I wanted to see how python's enumerate would look in scala with closure and implicit. I came up with this draft. Sorry for the formatting.

Below is the Enumerable class and an implicity function. These allow me to write:

scala> var a = Array("hello", "from", "enumerate")
a: Array[java.lang.String] = [Ljava.lang.String;@23245e75


scala> a.enumerate { (s:String, i:Int) => println(s, i)}
(hello,0)
(from,1)
(enumerate,2)


Here is the implementation:


class Enumerable(val array: Array[String]) {
def enumerate(op: (String, Int) => Unit) {
var i = 0
for(e <- array) {
op(e, i)
i += 1
}
}

}

implicit def enumerableWrapper(a: Array[String]) =
new Enumerable(a)
}

Rafael de F. Ferreira said...

Re: "Scala needs something like Python's enumerate function; if you want to loop each object in a collection but you need its index too, you have to do a manual for loop."

val ls = List("a", "b", "c", "d")
ls.zipWithIndex.foreach(println)

Jonathan Ellis said...

Thanks for the pointer, Rafael.

graham said...

groovy was originally inspired by python and is definitely the closest lanaguage for you to pick up. may people wrote it off because early version were pretty poor, but a new crop of developers took it over and turned it on it's head. i honestly think it is *the* easiest language to read because it is less magical than ruby but less verbose than java. not unlike python ;-)

i'd take a look at some of the groovy samples and some of the grails videos to see it in action. i think it would be much easier to adopt than scala, many people are wondering why it doesn't become java7 seeing as it has the features that people have been asking for (closures, type inference..).

on javascript, i disagree that javascript is much like java at all, their constructs can be very different. also, rhino is interpreted on the JVM whereas groovy is compiled to byte code so it enjoys good performance in most situations (with some well documented exceptions).

i'm primarily a java guy that would like to code more python, but we still have to deploy to a JVM and I find groovy a better way forward than any other option right now.

Anonymous said...

I couldn't figureout how to include dependent .scala script files( i.e. in the source form) ?