Archive for the ‘Software Engineering’ Category

Software Technologies that I MUST Learn

Monday, October 13th, 2008
news and informationbusiness,health,entertainment,technology automotive,business,crime,health,life,politics,science,technology,travel

Helpful friends and acquaintences often let me know about exciting new software technologies that I absolutely must know about.  I like learning about exciting new technologies.  Unfortunately, the software world is generating them faster than I can learn them.  Here’s my list of things I really must learn.

Programming languges

Dylan: A Lisp-family language developed by my friends.

ML: How can I be a “Lisp expert” and not know ML??

Haskell: Functional programming.  Alan Bawden says this is fundamentally different and I must know it.

Ruby: Up-and-coming popular language.

Subtext: Programming in trees instead of text.  (By Jonathan Edwards, MIT CSAIL.)

Hygenic Macros: A languages feature for doing macros (in the Lisp sense) cleanly.

Groovy: A dynamic language for the Java Virtual Machine.

Ron Garret’s paper on a module system for Lisp.

F#: Microsoft’s new function programming language.

LSharp:

Rlisp: A Lisp embedded in Ruby.

Programming tools and libraries

OProfile: The profiling tool for the Lisp implementation that I use.

Krugle:

LispBuilder: Access to SDL from Lisp for game development.

clbuild: An alternative to Lisp’s asdf-install: helps with download, compilation, and invocation of Lisp apps.


Networking

TRILL: New network protocol designed to solve the problems of the spanning tree.


Databases and Caches

Freebase: “Open, shared database of the world’s knowledge.”  From Metaweb, my old friend Danny Hillis.

CouchDB: Highly scalable document-oriented free DBMS written in Erlang.

Chubby: Google’s distributed lock system.

Google Sites: Web page design tool

Kompozer: Web page design tool

GORM:  Grails’s object-relatinal mapping tool, using Hibernate 3.

Terracotta: Clustering/caching tool for Java, making many JVM’s look like one.

Drizzle: Stripped-down MySQL, useful for caching too.

Whirlycache: A very fast cache

cl-prevalance:

Mongo: A grid-aware object-oriented DBMS from 10gen


Cloud computing

RightSize

Elastra

10gen

Web tools

Rails: (Ruby on Rails) Very popular, highly recommended by many people.

Grails: Rails for Groovy.  Built on GORM and Spring.

Google AppEngine:


Other

VMWare: Can I run Linux on my Windows box?

Software repositories: CPAN, http://planet.plt-scheme.org/, etc.

Jango: A Pandora alternative

I’ll get to them, really, I promise…

What Conditions (Exceptions) are Really About

Monday, March 24th, 2008
news and informationbusiness,health,entertainment,technology automotive,business,crime,health,life,politics,science,technology,travel

The “condition” (exception) feature of Common Lisp is important, but widely misunderstood, as can be seen by the frequent confusion between “conditions” and “errors”. I’ve been thinking about conditions and exceptions for many years, and here’s how I explain them.

Notes: I’m going to avoid using the word “error”, which has become overloaded. Some of the following applies to Java, but not all; I might write about Java exceptions in the future. I’ll omit the use of explicit catch/throw, for brevity. I’m only talking here about the simple heart of the condition feature, not fancy things like restarts.

Contracts, Bugs, and the Failstop Principle

Every function has a “contract” which defines what the function is supposed to do. If any function call violates the contract, the program must be incorrect: a “bug” has happened. The actual incorrect behavior might have started any time before we detect that there’s a bug.

If a program detects that a bug has happened, it should stop. That’s because if it keeps on going, there’s no way to know what it might do: write the wrong data to a file or database, display wrong answers, hang, etc. This is called the “failstop” principle.

(Exactly what “stop” means depends on the context. An interactive command might return to its event loop. A server thread might go back to its wait-for-input step. These are not perfectly safe, since the program might have corrupted transient state before the bug was detected. A safer way to stop is to kill the entire process. In Erlang, you only have to kill a thread, since each thread has its own transient state.)

Outcomes

The contract of a function specifies, among other things, the possible “outcomes” of calling the function. There is always one “usual” or “straight-line” kind of outcome, and then there can be zero or more “unusual” outcomes.

In Common Lisp, every function call either returns zero of more values, or else signals a condition. The caller discriminates on which kind of outcome this is by scrutinizing the values returned, or scrutinizing the condition that was signaled. The contract specifies the circumstances under which each kind of outcome happens, saying what values are returned or what condition object is signaled (plus what side-effects occurred) for each kind of outcome.

For example, suppose we call (open pathname :if-does-not-exist nil). Possible kinds of outcome are:

  • It returns a stream object. This means that the specified file has been opened for input.
  • It returns nil. This means that there was no file by this name in the file system. There are no side-effects.
  • It signals inappropriate-wildcard. This means that the pathname had was a wildcard pathname; it doesn’t make sense to open one. There are no side-effects.
  • It signals undefined-logical-host, and the instance’s undefined-logical-host-name is the name of the logical host. This means that it was a logical pathname whose host was not found in the set of translations.

(There are many other kinds of outcome. Sadly, Common Lisp does not actually specify what condition classes are signaled. You own contracts always should!)

If the call to open does any of these things, it is working properly and there is no bug. If the call to open returns something other than nil or an open-for-input stream to the specified file, or if it signals any other condition class, a bug has happened and the program should stop.

Conditions and bugs are entirely orthogonal. If you call open (as shown above) with a wildcard pathname, and it signals inappropriate-wildcard, that’s not a bug; that’s exactly what it’s supposed to do. If you call open and it returns a symbol, that’s bug, but no condition is signaled.

Commonly, when a function call ends with an unusual outcome, that’s specified to mean that there were no side-effects. There’s nothing theoretically wrong with specifying in the contract that a certain unusual outcome also has some side effects, but it’s not customary.

Tasteful Contract Design

When you design a function, you should first think of all the possible kinds of (correct) outcome. Then you should decide how each outcome will look to the caller: certain specific returned value(s), or certain specific conditions. This all becomes part of the contract for the function.

The general principle for making this choice is to consider which outcomes are the ones that a programmer is likely to expect and desire. You can’t always know for sure: different programmers might call the same function with different expectations. But it’s usually not hard to guess accurately. The “usual”, “straight-line” outcomes should always be a kind of returned value. The more unusual outcomes seems like it will be expected and important, the more likely you’d be to represent it by a kind of returned value than by a condition. All other unusual outcomes should be indicated by signaling conditions.

The main clue is the appearance of the function call. That’s mainly the function’s name, but it can also include the names of keyword arguments.

For example, (open "/a/b") should be defined to return a value only when it has actually opened a file, in which case it returns a stream. All other outcomes should be signals of conditions. However, (open "/a/b" :if-does-not-exist nil) suggests strongly that some outcomes (there’s no “b” in directory “/a”, or directory “/a” does not exist) should be indicated by returning nil, and conditions should be used for other outcomes.

Why Conditions are Better Than Special Return Values

It’s sometimes tempting to indicate unusual outcomes by having a function return a special value, or by having it return a second value. However, there are two drawbacks to this.

First, experience over many long years has shown that programmers often forget to check for the special values. Coding is hard and demands a lot of concentration. When a programmer is hard at work figuring out how to write an algorithm, it can be difficult to keep in mind all the possible outcomes of every call. There’s no excuse for it, but in real life, this is a common bug.

Bruce Eckel, in Thinking in Java, 2nd edition, correctly says:

In C and other earlier languages, there could be several of these formalities, and they were generally established by convention and not as part of the programming language. Typically, you returned a special value or set a flag, and the recipient was supposed to look at the value or the flag and determine that something was amiss. However, as the years passed, it was discovered that programmers who use a library tend to think of themselves as invincible — as in, “Yes, errors might happen to others, but not in my code.” So, not too surprisingly, they wouldn’t check for the error conditions (and sometimes the error conditions were too silly to check for [such as all the error values from printf]). If you were thorough enough to check for an error every time you called a method, your code could turn into an unreadable nightmare. Because programmers could still coax systems out of these languages they were resistant to admitting the truth: This approach to handling errors was a major limitation to creating large, robust, maintainable programs.

If an algorithm forgets to check for the special values, it will proceed as if the usual outcome happened. This means that the program is malfunctioning. A bug has happened but it has not been detected.

But if that unusual outcome is expressed as a signal of a condition, and the programmer forgets to handle it, the program will stop. This is what we want: failstop behavior.

(Exactly what “stop” means depends on context. In a server, there would probably be a handler-bind near the base of the stack that handles all conditions. This “ultimate handler” is called when a bug has been detected. It might write a stack trace to a log file, and then cause the thread to be restarted, for example.)

Second, even if you do remember to check for the special value, it often makes the program cluttered and harder to read. This is particularly annoying in Lisp, where it’s customary to write applicative forms where arguments to one form are themselves non-trivial forms.

I only have room here for a short example. The problems discussed above come up more often, and are harder to deal with, in much larger programs.

Suppose we have a configuration module that associates keys with URL’s. Looking up a key has two possible outcomes: the URL is found (usual) and no URL is found (unusual). The function url-host-name extracts the host name from an URL. If the URL does not specify a host name, that’s an unusual outcome. Finally, make-host creates and returns a host object, with the given host name.

We want to write a new function, get-host-from-configuration, which takes a configuration and key, and returns the host name of the specified configuration entry. There are two possible outcomes: the host, or an indication that we could not obtain it.

Version 1 disregards unusual outcomes:

(defun get-host-from-configuration (configuration key)
  "Returns the host associated with the key and the configuration."
  (make-host :name (url-host-name (read-url configuration key))))

Version 2 indicates unusual outcomes by returning nil:

(defun get-host-from-configuration (configuration key)
  "Returns the host associated with the key and the configuration,
or nil if it cannot be obtained."
  (let ((url (read-url configuration key)))
    (when url
      (let ((host-name (url-host-name url)))
        (when host-name
          (make-host :name host-name))))))

Version 3 uses conditions:

(defun get-host-from-configuration (configuration key)
  "Returns the host associated with the key and the configuration,
  signal host-not-in-config if the host cannot be found."
  (handler-case
        (make-host :name (url-host-name (read-url configuration key)))
    ((configuration-entry-not-found url-has-no-host) ()
        (error 'cannot-make-host-from-key :key key))))

Version 1 is nice and simple, but it doesn’t take into account the possibility of the unusual outcomes of its callees. Its contract cannot possibly be fulfilled.

Version 2 works, but it loses the applicative form. Every time we call a function, we have to stop, give the result a name, and check it before we can go on.

Version 3 keeps the applicative form. As long as everything has the usual outcome, it’s just like the simple code in Version 1. The “straight-line” code path is all in one place and easy to see. The infrequent unusual condition handlers are out of the way.

Conditions at the Right Level of Abstraction

You may be thinking: why not fix Version 1 by keeping the code, and just changing its contract to say

“Returns the host associated with the key and the configuration, signals configuration-entry-not-found if the URL was not found in the configuration, and signals url-has-no-host if the URL doesn’t have a host.”

In other words, we could make the callees use conditions, as with version 3, but just let the conditions propagate to the caller.

The problem with this is that it’s a modularity violation. The caller of get-host-from-configuration has no business knowing that there are URL’s involved at all. That’s an underlying implementation detail. Instead, get-host-from-configuration should indicate the unusual outcome, that it can’t make the host object, by signaling the cannot-make-host-from-key condition. It’s OK for the condition object to contain the key, since our caller clearly knows about the concept of keys since that’s an argument to get-host-from-configuration.

Similarly, it’s good for the read-url function applied to a configuration to indicate that it can’t find an entry by signaling configuration-entry-not-found rather than, say, file-not-found if the whole configuration file was missing. The caller of read-url has no business knowing whether the configuration is stored in a file or a database. We might even have two subclasses of configuration, file-configuration and database-configuration, but this would be hidden from the caller of get-host-from-configuration. Whether the configuration is stored in a file or a database is an internal implementation detail.

condition, serious-condition, and error Are Meaningless

Common Lisp defines three base condition classes named condition, serious-condition, and error. This is based on the misconception that you can tell whether the signaling of a condition is an “error” (bug) simply by knowing the class. But you can’t. Whether the signaling of a condition is a bug or not depends entirely on whether the function signaling it is defined to do so, or not. If I were designing a new dialect of Lisp, I would omit the classes serious-condition and error.

Why This Philosophy is Unconventional

Most explanations of conditions put little or no emphasis on functions having contracts that specify conditions. Few other explanations refer to the propensity of programmers to neglect to check special “error codes”.

Major Lisp texts, such as “Practical Common Lisp” and “Common Lisp: The Language, 2nd Edition” start off by acknowledging that signaling does not always mean that there’s an “error”, but they soon give up on that distinction. The word “error” is often used to sometimes mean what I call an “unusual outcome” and other times used to mean what I call a “bug”. I see these as extremely different phenomena that must be carefully distinguished.

The fact that the usual function for signaling a condition is called error greatly amplifies the confusion. If I were designing a new Lisp dialect, I would not call it that.

Bruce Eckel’s book says:

With an exceptional condition, you cannot continue processing because you don’t have the information necessary to deal with the problem in the current context. All you can do is jump out of the current context and relegate that problem to a higher context. This is what happens when you throw an exception.

As you see, that’s not how I would explain it at all. An unusual outcomes isn’t even necessarily a “problem”. It doesn’t mean you “cannot continue processing” any more than returning from the function means that.

Joel Spolsky doesn’t like exceptions at all. He considers them like “goto” statements, which everybody “considers harmful”, whereas I think that structured non-local exits do not have the problems cited in the “considered harmful” paper. He objects that “there is no way to see which exceptions might be thrown and from where”. But how are you supposed to program with functions whose contracts you do not know, exceptions or no exceptions? He says “they create too many possible exit points”; but whether you express unusual outcomes with exceptions or with special returned values, there are just the same number of them. He advocates using error codes, even though he admits that it makes programs far bulkier and makes it impossible to nest function calls.

Implementation and Portability Considerations

The Common Lisp specification makes tradeoffs between clean contracts and speed. For example, the addition function “+” ideally ought to be defined to signal a condition when either argument is a symbol. But, in order to allow generation of fast code on non-specialized hardware, its contract says that given a symbol, it may either signal, or return some integer value.

Some contracts in Common Lisp are deliberately incomplete in order to allow some implementations to add non-standard extensions.

Many contracts in Common Lisp do not specify particular condition classes to be signaled, but rather erely say that some outcome’s behavior is “a condition is signaled” without specifying a particular condition class nor instance variable values.

Topics For the Future

unwind-protect, unhandled conditions in cleanup handlers, chained conditions, Java exceptions, debugging, handler-bind, handling all condition classes, *break-on-signal*, polymorphism, with-error-context, condition names should say what happened, not where it happened.

Notes on the book: Dreaming in Code

Thursday, December 27th, 2007
news and informationbusiness,health,entertainment,technology automotive,business,crime,health,life,politics,science,technology,travel

I just finished reading an amazing book: “Dreaming in Code” by Scott Rosenberg. Like many good, recent non-fiction books, it alternates between a specific narrative with colorful real people, and general background information. In this case, it’s the story of Chandler, a personal information management tool, and the team who are building it, led by Mitch Kapor.

The general background explains far more about real, contemporary software, how it is built, and what it’s all about, than anything I’ve read before. Everyone learning to be a software engineer, or who wants to understand what software engineers actually do, should read this book.

In only 355 pages, Rosenberg discusses, in clear language that’s easy to follow, at least the following:

  • What working on a software project in a team is like, the subjective experience
  • Open software, and the “Cathedral vs. Baazar” concept
  • Doug Englebart’s ideas (very germane to Chandler)
  • Famous software fiascoes
  • Computer languages, especially Python and how it compares to others
  • Reusable software, software libraries, build versus buy
  • What “geek” really means
  • CVS, Bugzilla, and Wikis
  • Why user interfaces are so hard to design
  • Dependencies between parts of a system and how they block work
  • Release management and scheduling
  • Specifications and their nature
  • Layers of abstraction
  • Scaffolding
  • Code reviews
  • WebDAV and CalDAV
  • Microsoft FUD
  • Requirements analysis
  • Methodologies: waterfall, agile
  • The gist of No Silver Bullet and The Mythical Man-Month
  • Ruby on Rails
  • Software engineering, its history and what it means
  • Complexity
  • Late binding
  • Object-oriented programming
  • Recursion
  • The halting problem

The story of Chandler and the team is compelling and instructive. On page 173 of the book, he says: “By now, I know, any software developer reading this volume has likely thrown it across the room in despair, thinking, ‘Stop the madness! They’re making every mistake in the book!’” I did indeed feel that way by page 173. Here’s my sense of what went wrong, based on the account in the book:

  • They did not have one architect (Brooks makes a very good point about why there should be a single person)
  • They didn’t work out the architecture in advance, and they went back and changed it many times
  • They had a very flexible data concept/model, in which items change type frequently in a user-visible way, which they didn’t work out until quite late
  • They kept changing their mind about their UI substrate: wxWidgets? Mozilla internals?
  • The software ecosystem changed around them after all those years, and using a Web UI now made sense, but it was too late for them
  • They could not figure out what database technology to use (they finally decided not to use the Zope Object Database, although their reasons for that decision don’t impress me)
  • It was originally supposed to be peer-to-peer, but they could not figure out how to make that work, so they changed it to be server-based, a major change very late in the design
  • They had to design a security model for all this
  • It was all extensible, which is great but takes a lot of work to do right
  • There were complicated semantic issues with sharing, “chain-sharing”, etc. which were not worked out early.
  • They wanted to have extensional and intensional collections, like iTunes, but also wanted to combine the two (the so-called “exclude Bob Marley” feature), which makes the semantics a lot harder
  • Their internal terminology was inconsistent, symptomatic of a lack of architectural integrity
  • They did serious requirement analysis only late in the project
  • It was putatively open-source, but it was much too immature to really get outside developers involved
  • They were too focused on doing “the right thing” instead of getting something out fast; see Gabriel’s “Worse is Better” paper
  • They released much too early, partly because of the glare of publicity due to Mitch Kapor’s involvement

I see that they are still in “preview” releases. This has been going on for six years now! They have no projected release date for 1.0. It will be free, under the Apache license.

I have always wanted a good personal information manager, and a lot about Chandler looks very promising. Someday I may be a happy user. Right now, I think I’ll wait until release 1.0.

I hope they have moved beyond the problems illustrated in the book and are running smoothly now. Kudos to the whole Chandler team for letting Rosenberg be so involved, being so honest with him, and letting him produce this unique, spectacular book.

Be a Mentor

Tuesday, December 25th, 2007
news and informationbusiness,health,entertainment,technology automotive,business,crime,health,life,politics,science,technology,travel

Developing software can’t be learned in a classroom. To be sure, there are plenty of things that you can learn in a classroom that are invaluable. But if you want to be a software engineer, you have to learn by doing.

When I showed up at M.I.T. as a freshman, I had learned computer programming at summer schools. My regular school didn’t have any computers (this was the early 1970′s). The only programs I had ever written were homework assignments, and little toys for myself. I had never worked on, or even read, anything large, or anything that needed to be maintained over time.

I was set to work writing an Emacs in Lisp for the Lisp machine. This was quite a big change! During my time as an undergraduate I wrote a lot of system software for the Lisp machine (and a little for the ITS timesharing system), and I think it was pretty good code, better as the years went by. But when I look back, I marvel that I was able to get going so quickly. I’m a pretty bright person but no genius; I know dozens of people personally who are way smarter than me. I now attribute it to two things. First, I read lots and lots of real software, studying it line by line. Second, I had a great mentor.

After Richard Greenblatt hired me at the M.I.T. Artificial Intelligence lab, my first task was to learn Lisp. I didn’t know how to go about doing that effectively. Greenblatt told me to write a chess program, and I tried that, but I found myself doing low-level array stuff (how does a knight move?) and it was just like programming in Basic again. I had observed that this guy Dave Moon seemed to be one of the very respected hackers (I use the word in its original sense) at the Lab, and although he seemed a bit unapproachable at the time, I asked him how to learn Lisp, and he told me to write a symbolic differentiator. That was a much better approach.

Moon was also working on the Lisp machine software, and there were only a few of us, so he spent considerable time helping me get up to speed. He reviewed all my code and gave me extensive feedback, and he answered all my questions. I read all of his code and did my best to emulate it. We worked very closely, even sometimes sitting at the same console taking turns typing.

For me, it was an apprenticeship. Although the classic “apprentice” that you read about in historical books spends years doing junky, boring work, whereas I was doing the good stuff right away. Although my reasons for personal bias are obvious, I think Dave Moon is one of the dozen best programmers in the world, and I know many others who have similar respect for his depth of understanding as well as coding abilities. To have stumbled upon having him as a mentor is one of the luckiest things that has ever happened to me.

I have tried to “give back” the good fortune that I’ve had. I’ve never had a full-time apprentice, but I have tried to help other hackers whom I’ve worked with. And this year I’m helping to teach a class in Java Distributed Programming at Harvard Extension School, providing several students with the first detailed code reviews they’ve ever had. I’ve also recently submitted my name to an M.I.T. mentoring initiative, volunteering to be a mentor. We’ll see what happens with that.

I’ve learned a lot from many people. Prof. Gerry Sussman at M.I.T. is a superb teacher, who has lots of apprentices. I never apprenticed under him, but I learned a lot from his classes and many personal conversations. Guy Steele and Tom Knight were also particularly influential. And I keep learning from my co-workers.

You don’t have to be a stellar hacker to be a fine mentor. Give younger people an opportunity to do real, production programming. Keep a close eye on their work and help them improve it. Help them learn the lessons that can’t be taught in classrooms: how do real software projects go, how do you work well with other hackers on a team, why it’s so important to strive for simplicity, and so on.

Ideally, find a promising beginner who you’ll be working with for a year or more, someone you’ll enjoy spending a lot of time with, and start mentoring him or her. You don’t have to say anything or make any formal offer. Just do it, and see how it goes.

The Scala programming language: My First Impressions

Tuesday, December 25th, 2007
news and informationbusiness,health,entertainment,technology automotive,business,crime,health,life,politics,science,technology,travel

I keep coming across praise for a new programming language called Scala. I looked into it a bit, and here are my first impressions. I have not written any programs in it, so I am hardly even a beginner, let along an expert. My own opinions are in parentheses. Please comment on this post to correct my errors.

I started with the JavaPolis ’07 interview with Martin Odersky. (He’s the kind of person I like: clear, cogent, practical, charming, and modest.) I then downloaded it.

History: The key inventor is Martin Odersky, who heads the programming research group at Ecole Polytechnique Federale de Lausanne as a full professor, and was one of the designers of Java generics. He was a student of Wirth and came from the Modula-2 tradition, but later got interested in functional programming, and is now associate editor of the Journal of Functional Programming. He’s been working on Scala for over five years. He originally used Scala in classes, teaching Java first, and then Scala in the next year as a “power Java”. The first public release was in 2004, and he revised it substantially in 2006. There has been a series of versions, maintained with back-compatibility and a deprecation protocol. The current version is 2.6.

What’s it for?: It is intended to be a general-purpose language that could replace Java. So far it has primarily been used for web-related applications. The first industrial users were a company called Sygneca in the U.K., who have used to build web sites for agencies of the British government. Perhaps the best-known development has been David Pollack’s Liftweb, a web framework along the lines of Rails, which is getting a lot of attention and has many committers. See .

Documentation: Odersky recommends starting with “First Steps To Scala” (also in the distribution). Then, you can move on to the book “Programming in Scala”, by himself and others, which just came out on Dec 12 (two weeks ago, as I write this). You can get the PDF for US$22.50. It assumes you know Java. The distribution comes with a reference manual.

Functional programming: Scala is intended to be a fusion of functional programming and object-oriented programming, rather than a “pure” function language like Haskell or ML. Ordinary imperative programming works fine. Objects can be mutable or immutable. The latter is preferred when it’s possible, since it needs no concurrency control. Also, these days it’s faster to make new objects and allow them to be efficiently GC’ed, than incur the GC overhead that results when you mutate an existing object (interesting point!). There are mutable arrays, but immutable (parameterized) List objects. (I am entertained that the infix operator “::”, which makes a new List with an element prepended, is pronounced “cons”!) “Nil” creates an empty list (unlike Lisp, lists are first-class). The lexeme “=>” is used to define anonymous functions (what Lisp people call lambda expressions), so you can do mylist.filter(s => s.length = 4). There are also immutable “tuples” whose elements can be of any type and which have a very simple creation syntax: (52, “Locust”). (These are even more like Lisp lists). One thing you’d use this for is multiple-value return.

Object-oriented programming: Notice how few explicit type declarations there are:

class SimpleGreeter {
val greeting = "Hello, world!"
def greet() = println(greeting)
}


val g = new SimpleGreeter
g.greet()

There are no static fields or methods. Instead, you use singletons. The concept of singletons is built into the language, so the syntax is concise and stylized. (I’ve said before that the famous “Design Patterns” are often just conventions that make up for things that the language cannot do itself. Here’s another example of a pattern that’s no longer needed as a pattern.) There are “traits”, which are like Java interfaces except that they can define default method implementations. Although Scala is “single inheritance of implementation” like Java, there’s a way to use traits that provides a simple “mixin” facility.

Interpreter: Scala has an interactive interpreter (what Lisp people call a “read-eval-print loop”) (right there, we’re way ahead of Java!). You can define variables without specifying the type; it infers it. Here’s a simple function definition:
def max(x: Int, y: Int): Int = if (x < y) y else x
Parameter types are not inferred, so they must be specified. But in some cases, including this one, the result type is inferred.

Concurrency: There is a library trait called “Actor”. It’s based on the concepts in this paper and this paper, which I have not yet read. It looks like it’s oriented around asynchronous messaging.

Sharing of libraries: There is a system called Scala Bazaars, or “sbaz”, to help the open source community share libraries. There appear to be around 250 contributions already.

Some other interesting features: The syntax of XML is embedded in Scala. There are primitives for pattern matching (what Lisp people would call destructuring). There are user-defined annotations.

Implementation: The main Scala compiler produces Java class files; It can operate seamlessly with Java. (This means you get an excellent JIT compiler, an excellent GC, and lots of libraries, a huge plus for a new language.) There’s also a compiler that makes binaries for the .NET CLR.

Interactive development environments: It comes with GNU Emacs support, and there are plugins available for Eclipse and IntelliJ IDEA.

Persistence: It works with the db40 object-oriented database system.

Summary: I feel that the way functional, object-oriented, and imperative programming are combined in Scala is much like the way they are combined in Lisp. As compared to Lisp:

  • conventional syntax; more approachable to many people
  • no Lisp-like macros
  • much cleaner (anything is cleaner than Common Lisp, of course)
  • statically typed with inferencing: the best of static typing without the worst parts
  • no ability to incrementally recompile and re-run (as far as I can see)

The emphasis on immutability and the Actor class also makes me think of Erlang, but I know too little about both Scala and Erlang to venture further comments.

It looks extremely promising. I’ll be keeping an eye on this.