We all know the story of how Steve Jobs back in the days went to visit Xeroc PARC, and then ran home and built the Macintosh - an insanely great thing. What he saw at PARC was a computer with windows, with a mouse, with drawing capability; the Smalltalk computer.
Since then, Smalltalk has had its share of dedicated followers and - seemingly as important - has been a source of inspiration for every object oriented programming language since. When Steve Jobs went to start NeXT, the Objective C language was born, borrowing as much as practically possible from Smalltalk. Java was inspired by both Objective C and Smalltalk. Ruby's creator, Matz, was inspired by Smalltalk, and Smalltalk served as the inspiration for Perl 6's object model design.
And still, most of us have never even tried it.
I've spent the last few weeks getting aquainted with Squeak - an open source Smalltalk implementation, and I'm totally blown away by what it has to offer. The first obstacle you'll meet is that Squeak is really different from any programming environment you've ever used. The programming language itself is really dead simple, but the environment is different. First of all, Squeak is more like an operating system than a programming language. When working in Squeak, you'll be working on an image - which is a snapshot of code, state and graphical elements. Your classes and objects don't live in files, like you're used to, but rather as objects inside this image. You won't be able to immediately start using any old text editor to edit your code, but instead you'll be using things like the Object Browser. Don't let this put you down, I guarantee you'll find it's worth it!
As as example, imagine a trivial Ruby application with a couple of classes. Usually, each of these classes are defined inside a file - but you can still extend them in other places, usually by some kind of meta programming technique. As a consequence, the exact definition of a class is somewhat hard to find except at runtime. Depending on what files are loaded and what commands are issued, your classes will change behaviour - one of the main reasons nobody as yet has been able to build things like refactoring support into a Ruby IDE; while you're programming it's practically impossible for your programming environment to know the current state of any object; be it a class, module or any other object.
In Smalltalk, however, there really isn't a distinction between runtime and programming time. If for instance you discover a bug in your application code at runtime, you can bring up the debugger and locate the bug. Then, inside the debugger, you can fix the bug, accept the change and resume operation. And from that point on, the bug is no longer inside your application; you changed the class definition in the debugger, and it's immediately fixed wherever the class is referenced.
If Smalltalk had files defining the classes, and then loaded these files at startup, this wouldn't be possible. For me this demonstrates that classes are actually more Object-like in Smalltalk than in say Ruby. Just like you can change the data in your objects, you can change the behaviour of your code without rebooting the entire system.
One of the hardest things to grasp was how to create a class in
Squeak. Since there are no files defining classes and no
class
keyword to define classes I couldn't quite
figure out how to create a class. As it turns out, the way to
create a class is to send a message to another class:
Object subclass: #NameOfSubclass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'AST-Tokens'
So by sending this message a new subclass (Person in this example) will be created and immediately available all over. And where can you interact with your newly created class? Anywhere, really. You can open up a Workspace (like a text editor window) and type Smalltalk code into it. Select the text and click Cmd-d (to do it), Cmd-p (to print it), Cmd-i (to inspect it). Or you can use the Browser and work with your classes there. It takes a little getting used to, but after a while it feels like the most natural way to interact with your classes.
Another advantage with an image based system is that state is preserved for you. If you open a Workspace and define a variable, you can save your image, forget all about it for months and return to find your variable still available in memory. Compare that to an IRB session, where everything goes away before you can type Ctrl-d.
Know what? The methods in your classes are objects too, they even
have history. If you create a Person class and give it a
meet:at:
method you can use to introduce a Person
instance to other Person instances at a place and then change your
mind about the implementation, you just might regret it at some
time. Which is the reason any professional uses source control
management to track changes in his source code. In Squeak, the
objects track changes in methods for you, so you need not worry if
you forgot to commit a change before you changed something. Just
pop up your Browser, select the Person class and the
meet:at:
method. Click the Versions button, and
Squeak will give you something like this:
Here you can see that we changed the method comment, and Squeak lets us revert to an earlier version of our method implementation should we change our minds.
A minor detail: Ruby, like a lot of programming languages, uses the dot (.) to separate an object from a method in a method call (Smalltalkers would refer to this as receivers and messages). So, strictly speaking, the way of adding two numbers in Ruby is:
1.+(2)
However, this is so ugly that people would probably not accept it. So Matz added what is referred to as syntactic sugar which lets you say:
1 + 2
You can skip the dot, skip the parentheses and even put in a space to make it look like a mathemathical operation. The ugly truth, however, is that it's a hack.
In Smalltalk a receiver (the object that receives a message) is separated from its message by one or more spaces:
1 + 2
This is a so-called unary message, and this is the formal way of sending it. Smalltalk also has keyword messages, which again are simulated in Ruby by using hashes:
person.name = 'John', :address => 'Milky way'
What this really boils down to, however, is this:
person.name=('John', {:address => 'Milky way'})
Not that pretty, is it? In Smalltalk, this kind of messages are called keyword messages, and are called as such:
person.name:'John' address:'Milky way'
And the message is defined as and referred to as
Person»name:address:
. Ruby 1.9 mimicks this behaviour, but
not quite.
One of the first things any newcomer to Ruby falls in love with is
the fact that even the most primitive things are pure
objects. Whenever you show off Ruby, typing stuff like
1.day.ago
into an IRB session, any java guy will be
impressed that you can call methods on the object 1; that it's
really an object. Well, Smalltalk takes it further. I already
mentioned that classes are created by sending messages to a Class
object, how about looping in Ruby? You'd do something like
while my_bottle.contains_beer? drink_some_more end
So what does this while
thing mean? Is it a method? Well,
no. It turns out it's one of Ruby's keywords - along with
unless, until, yield, when, in and others. A keyword is like a
method without a receiver, as you'll have noticed if you ever
tried to give your class a and
method for
example. This is Ruby's way of telling you that OO is OK in most
cases, except:… Just like Java tells you objects are okay except
for really rare stuff like Strings, numbers and the
like. Smalltalk, on the other hand, has only 5 keywords: self,
super, true, false and nil. And they're not even keywords but
pseudo variables, but we'll leave it at that.
So the way to do a while loop in Smalltalk is obviously to send a
message to some kind of object. In this case, the object in
question would be a code block, and the message would be
whileTrue
.
[myBottle containsBeer] whileTrue: [drinkSomeMore]
The stuff inside the square brackets are Smalltalk blocks, so this
example has a first block which evaluates to either true or false;
which is sent the message whileTrue: with a block to be executed
while the first block evaluates to true. The same goes for
if/else; you send the ifTrue:
/ ifFalse:
message to something
that evaluates to either true or false along with a block to
execute.
As I mentioned, it does take some effort to grasp the notion of an image based system. I downloaded the Squeak by example guide to Smalltalk, and read it on my way to work every day. It took me three days (two hours reading) to start liking Squeak, another three days to start understanding it, and that's where I am right now. I think I'm even more inspired by Squeak and Smalltalk than I was about Ruby when I started reading the Pickaxe six years ago. Unlike the situation when I started learning Ruby, there is a very attractive web framework for Smalltalk, so if you're doing web development, you really need to look into Smalltalk.
The thing I'm finding it hard to accept, however, is that this thing has been around for more than 25 years; and people are still programming like they did in the seventies. I just don't get it.