Introduction Before I found Scala I was looking for a language with the following characteristics:
- Expressivity on par with Python or Lisp
- Performance on par with Java
- Has a REPL or at least an interpreter
- Compiled
- Object-oriented
- Large number of modern libraries and frameworks
- Cross platform, including think-client GUIs
- Open Source
- The Scala implementation is more explicitly structured. Some of the structure, such as the static typing, is forced by Scala. Others, such as using classes instead of conventions on list contents to distinguish between normal conditions and "executing conditions," are not forced by Scala but are simply easier and more natural.
- The resulting plan is a list of operators rather than a list of lists obeying a convention. This is straightforward because "executing conditions" are a special class of condition and are explicitly tied back to the operators they represent.
- The core algorithm in Scala is completely and explicitly devoid of mutable state. The Lisp solution makes only one small use of mutation in achieve-all, and that occurrence could easily be removed in the same was as it was from Scala. However, cons cells, and the lists they form, are mutable and therefore it is much more difficult to prove that the algorithm uses no mutable state.
- The Scala solution required fewer utility functions. This is due to both the richer standard library and case classes.
- The problem-definition DSL required significantly more code in Scala, especially in order to make it interpreter-friendly.
- The syntax of the problem-definition DSL in Scala is statically checked. For example, you cannot use preconditions in the place of the add list. Achieving this took a fair amount of work, and I almost just went with a looser version that was equally easy to type and read but less validated.
- In my subjective opinion, the Scala version is much easier to read. I find the fact that Lisp control structure like "if" implicitly return nil on failure if not "else" is provided to be quite confusing.
- At least for this problem (which didn't use macros), Lisp code could be almost directly converted to Scala.
- Scala implicits make an effective substitute for special variables (i.e. defparameter) in Lisp.
- Overall LOC count is too close to matter.
- Lisp development is far more interactive that Scala.
- The Scala compiler catches a lot of "stupid" mistakes that the Lisp compiler does not (but the Lisp compiler catches some, much more than Python, Ruby, et. al.), reducing the number of edit/run cycles by a fair margin.
- Case classes are really useful. They allow you to add structure to your program without going to all the work of implementing all the support methods, such as equals, hashCode, toString, and unapply for pattern matching. Lisp is worse than Java et. al. because it has four different equals functions (eq, eql, equal, equalp) all with subtle (and not so subtle) differences. In Scala, if you are wise and don't have to deal with Java libraries (hah!), you pretend eq (reference equality) doesn't exist (indeed, pretending references don't exist, and null doesn't exist, seems like a good idea to me). In fact, I find case classes so useful, I think I'm going to write a Python metaclass so I can use them in Python, too.
- I retract previous negative statements about pattern matching on lists. It's useful. I get it now. But I still wouldn't convert a string to a list just for pattern matching.
10 comments:
Hi Erik, the link to the scala code seems broken.
alex
Thanks for the heads up! It's fixed now.
Did you forget to finish point 6 of 'General observations'?
I obviously need to read what I write more carefully. Broken links and unfinished thoughts...you'd think this was a hobby or something...
Point 6 under general observations is now complete.
I read this post yesterday after you published the link on TSS. Great post. I downloaded the Scala code and am looking it over. The code gives a better flavor for Scala's power than the simple examples I've seen elsewhere.
Hi Erik, great post! I didn't consider Scala until I read it. I'm starting to change my mind now.
Have you considered OCaml or F#? They are both much faster than any of the other languages you discuss, for example.
Jon - I've been considering taking a look at both those languages, but F# is not open source and for Linux/Unix would be dependent on Mono, which, not surprisingly, seems to always lag behind Microsoft's .NET implementation and not be completely compatible. I think what the Mono project has produced is very impressive, but I also think it will always be a behind the MS .NET runtime and libraries.
Quick perusal of the OCaml website leads me to believe that it doesn't have the breadth of libraries that I would like. One of the aspects of Lisp that frustrates me is that while there are tons of libraries out there for it, simply too many of them are in a pre-release state, neglected, or both. This seems to be common with "fringe" open source languages.
Scala gets around it by being Java compatible. I imagine F# is the same way with .NET. If .NET were as cross-platform as Java I would give F# a very close look, but as far as I can tell it is not.
One more language that I suggest you to look through is Nemerle (nemerle.org). It is .NET-based language, but I like it even more then Scala. First of all, I was very impressed with its macro system.
Hi Erik,
thank you for this post. I am implementing GPS with Scala 2.9.1, and wanted to take a look at your solution, but the url seems to be locked.
Ignacio
Post a Comment