At lunch today, we had a lengthy discussion about the merits of various .NET technologies, including LINQ. I complained that, although I like LINQ, and I like C#, I cannot help but be annoyed that many of these “cool” language features in C# are nothing more than libraries in Smalltalk. Joel responded that the comparison wasn’t fair; C# allows you to invent more syntax than those languages permit, and afford greater flexibility.

Without disagreeing, let’s visit some specific examples. The code is written for GNU Smalltalk and written slightly Algol-y on purpose, to make it easier for non-Smalltalkers to follow. In other words: if you program Smalltalk, don’t bother telling me I’m eschewing a more functional idiom for a more explicit one. I know.

The ?? operator

One C# feature that Joel specifically mentioned was the ?? operator. In C#, this operator returns the expression to the left of the operator if it is non-nil, or that to the right if it is.

It turns out that you can add this exact operator to Smalltalk trivially. In Smalltalk, everything is an object—including nil, which is the singleton instance of UndefinedObject, which is a subclass of Object. Thus, to add ?? to the language, we just have to add a ?? method to the Object class:

Object extend [
    ?? default [
        ^ self isNil ifTrue: [ default ] ifFalse: [ self ].
    ]
]

Let’s test it:

st> 5 ?? 0.
5
st> nil ?? 0.
0
st>

Perfect.

Well, almost. Just like the ? operator, the right-side of the ?? operator in C# only gets executed if the left side is null. Ours executes the right side greedily.

Thankfully, it turns out that we can fix that easily, too. In Smalltalk, whenever you wish to indicate that something may be executed later, you stick it into a lambda, which is simply code enclosed by brackets. Lambdas can be evaluated by calling value. Thus, although we need to make our method slightly more complicated:

Object extend [
    ?? default [
        ^ self isNil
            ifTrue: [
                (default respondsTo: #value) ifTrue: [default value] ifFalse: [default]
            ]
            ifFalse: [ self ].
    ]
]

…we can have our cake and eat it too, using the simple syntax when it’s okay to be greedy, and the more complex one elsewhere:

st> 'foobar' ?? 'cow'.
'foobar'
st> 'foobar' ?? [ Object anUndefinedMethod ]
'foobar'
st>

Most Smalltalks actually already have this operator, calling it ifNil:. But the point is to show that adding language features like this is easy, and can be done by the programmer—not the compiler designer.

Message-eating nil

Of course, we can one-up that behavior. In some languages—notably, Objective-C—trying to call methods on nil does not generate an error. Instead, nil silently eats the message and returns nil. Although you may gasp and say that’s the dumbest thing you’ve ever heard of, the overwhelming majority of Cocoa programmers would agree that message-eating nil is a great feature that ends up being far more useful than harmful. Sadly, Smalltalk’s nil raises an exception, just like C#'s and Java’s—a behavior that, admittedly, does have its uses. Wouldn’t it be nice if you could choose which behavior we wanted in which context, without having to rewrite tons of code?

Turns out that you can do that via a library in Smalltalk. Nevin Pratt has already written a library called “Message-eating null”, currently maintained by Keith Hodges, that does exactly that. How can it work?

The library defines a new class called Null, and a new singleton, null, to parallel UndefinedObject and nil. Like UndefinedObject, Null instances respond true when asked isNil, making them appear identical to most code. Unlike UndefinedObject, Null simply returns itself when sent pretty much anything else.

Now, I have the best of both worlds: if I want message-eating, I return null. If I want exception-raising, I return nil. No other code has to be any the wiser. That’s something you cannot do in C#.

LINQ

Smalltalk has actually had LINQ-like expressions since its inception. Code like the following is common:

((people
    select:  [ :person | person type = #adult ])
    reject:  [ :person | person location = 'New York' ])

which is roughly equivalent to the following LINQ:

from person in people
where person.Type = PersonType.Adult && person.Location != "New York"
select person

Unlike with LINQ, if these operators did not exist in Smalltalk, it would be trivial to add them. In fact, their implementation in Smalltalk is at the library level, not the language level. Here’s the code to select: in GNU Smalltalk, if you’re curious:

select: aBlock [
    "Answer a new instance of a Collection containing all the elements
     in the receiver which, when passed to aBlock, answer true"

    <category: 'enumeration'>
    | newCollection |
    newCollection := self copyEmpty.
    self
        do: [:element | (aBlock value: element) ifTrue: [newCollection add: element]].
    ^newCollection
]

I imagine your response at this point is, roughly, Big whoop. So you had LINQ before C# did. It has it now, and, honestly, I’m never going to want anything other than select:, reject:, collect:, inject:into:, and a couple of others. Why do I care?

Easy: because although Smalltalk was never designed to support relational databases easily by this syntax—a key feature of LINQ—it does. Via libraries.

LINQ to SQL

Because Smalltalk needs no special syntax to support comprehensions, it’s trivial to add them to other libraries, such as ORMs. One such library, ROE, which ships with GNU Smalltalk, allows you to write the above query against a database as follows:

((people
    select:  [ :person | person type = #adult ])
    reject:  [ :person | person location = 'New York' ])

Like LINQ to SQL, this code returns a promise—not an actual result. It’s not reified until you attempt to access some elements, at which point the actual SQL is generated and sent to the database for execution. We achieved these lazily returned, database-backed collections without modifying the language at all; we merely needed to write a small library.

Of course, databases are different from in-memory collections. The query generated from the above code would return the full tuple for every row in the database—potentially very expensive if the table backed by people has many columns. ROE provides an easy solution via the project: and projectAll: methods, which take one and multiple column names, respectively, to return from the database. Thus, if we only cared about first names, we might write:

((people
    select:  [ :person | person type = #adult ])
    reject:  [ :person | person location = 'New York' ])
    project: #firstName

Of course, the default collections don’t support project:—it doesn’t make much sense there, since, as in Java, you’re really only getting a collection of pointers to the objects in the collection, which is a cheap operation—but what if we wanted to add it there for consistency? No problem:

Collection extend [
    project: aField [
        ^ self collect: [ :each | each perform: aField ].
    ]

    projectAll: fields [
        | d |
        ^ self collect: [ :each |
            d := Dictionary new.
            fields do: [ :field | d at: field put: (each perform: field) ].
            d.
        ]
    ]
]

And, suddenly, every collection that subclasses Collection—that is, all of them—can use my new project: method. I don’t need to worry about whether I’m talking to a database or a local collection; they all can do it.

Your language features are my libraries

I guess this is why, despite all of its faults, I have a lot of trouble giving up on Smalltalk. C#'s a good language, and .NET’s a good framework; but I cannot help but feel that this isn’t an issue of reinventing the wheel, as much as forgetting that we can provide programmers the tools to make their own types of locomotion.

When you hear Smalltalkers complaining that it’s all been done before, this is what they mean. Not that any particular language feature already exists, but rather, that they could have written it without switching or upgrading their language.