Why I love Smalltalk

This post was extracted from a small talk I gave at Simplificator, where I work, titled “Why I love Smalltalk and Lisp”. There should be another post, “Why I love Lisp” following this one.

After I learned my basic coding skill in more or less traditional languages, like C, C++, Python, there were four languages that really taught me something new. Those languages changed my way of thinking and even if I never use them, they were worth learning. They are:

Smalltalk

Lisp

Erlang

Haskell

You can probably add Prolog to that list, but I never learned Prolog. This post is about Smalltalk.

My goal is not to teach Smalltalk but to show things that you can do with Smalltalk that you can’t do with any other language (disclaimer: surely other languages can do it, and we’ll call them Smalltalk dialects). Nevertheless I need to show you some basics of the language to be able to show you the good stuff, so here we go, a first program:

1 + 1

That of course, evaluates to 2. If we want to store it in a variable:

m := 1 + 1

Statements are finished by a period, like this:

m := 1.
m := m + 1

In Squeak, a Smalltalk implementation, there’s an object called Transcript and you can send messages to it to be displayed on the screen. It’s more or less like a log window. It works like this:

Transcript show: 'Hello world'

and it looks like this:

The syntax is quite unique to Smalltalk. The message, otherwise known as “method call” in other languages, is called show: (including the colon) and it takes an argument. We can run it 10 times in a row with the following snippet:

10 timesRepeat: [
Transcript show: 'Hello world'
]

There you can start to see how Smalltalk is special. I’m sending the message timesRepeat: to the object 10, an Integer. Doing something N times repeatedly is handled by the Integer class, which if you think about it, makes sense.

The second interesting part, is the block. The part inside squared brackets. You might thing that’s the equivalent of other language’s block syntax, like in this Java example:

for(int i=1; i<11; i++) {
System.out.println("Hello world");
}

but Smalltalk version’s is a bit more powerful. It’s a real closure. Look at this:

t := [
Transcript show: 'Hello world'
]

Now I have a variable named t, of type BlockClosure, and I can do anything I want with that variable. If I send it the class message it’ll return its class:

t class

and if I sed it the value message, it’ll execute and leave a “Hello World” in the transcript:

t value

Let’s see some more code. A message without any arguments:

10 printString

a message with one argument:

10 printStringBase: 2

and a message with two arguments:

10 printStringBase: 2 nDigits: 10

Isn’t it cute? That method is called printStringBase:nDigits:. I never seen that syntax anywhere else; well, except in Objective-C, which copied it from Smalltalk.

Notice that a class is created by sending a message to another class telling it to subclass itself with the name and a few other arguments. It’s a message, a method call like any other. Object is a class, classes are objects. The object model of Smalltalk is a beauty but that’s a subject for another post.

Now that we have a class, let’s create a method called greet: in that class.

In that method definition first we have a comment for the method, then the list of local variables within pipes (“|”), and then the implementation, which sets the variable message to contain “Hello ” and the comma concatenates name to it. Then we just send it to the transcript.

It looks like this:

Ok, let’s use it:

m := MyClass new.
m greet: 'Pupeno'

To create an object of class MyClass, we send the new message to that class. There’s no new keyword like in Java. new is just a method. You can read its code, override it, etc. Don’t mess with it unless you really know what you are doing.

Actually, if you think about it, we haven’t seen a single keyword. Look all the code we wrote without having to memorize any keywords! What’s even more important is that by now you essentially know Smalltalk. That’s all there is, but like LEGO bricks, this simple and small building blocks allow you to build whatever you want.

Yes, that’s it, that’s all there is to it. We already saw that Smalltalk doesn’t need loops, it has integers and that class implements the timesRepeat: message which allows you to do something N times. There are many other looping methods here and there.

What about the if keyword you ask? Surely Smalltalk has an if? Well, no, it doesn’t. What you can recognize as an ifis actually implemented in Smalltalk using the same mechanism of classes and message passing you saw already. Just for fun let’s re-implement it.

We starte by creating the class PBoolean and then two classes inheriting from it, PTrue and PFalse.

This beauty and simplicity in language constructs can also be seen in the lambda calculus itself, concatenative languages (like Factor) and Lisp dialects (like Racket) — or even more in Kernel, where you can derive all constructs in the language from 3 primitives (no special forms).

But Smalltalk has a lot of neat things going for it indeed. Have you looked at Self and Newspeak yet? The latter is still my favourite Smalltalk dialect.

SmallTalk was also a foundational language for me. As were Prolog and FORTH. Prolog was interesting but I have found few uses for it. FORTH OTOH is an ever-present member of my toolbox, primarily as an embedded debug tool in pretty much everything I do, both major OS apps and embedded systems. So much so I have written a tool that generates FORTH wrappers from a C .h file.

I stopped using SmallTalk after discovering a side-effect of the Closure definition that (as I was told, snottily, by an engineer at DigiTalk) was as described in the language definition:

You can declare local variables in a closure. If you then run more than one instance of the closure – e.g. using fork: – you do not actually get multiple instances of the closure. There is in fact only one instance and all parallel invocations use the same local variable. Yes, there are multiple somethings doing work, but the state is shared between them. So not really closures at all. Either that or fork: needs re-defining so it does make a copy.

Because I have some SmallTalk in my cv, I occasionally get head-hunter queries. Seems SmallTalk is still used heavily in banking applications.

BTW, Objective C borrows heavily from SmallTalk in the area of call syntax.

I am not sure about Squeak, but in VisualWorks (which is also free for private purposes) blocks are reentrant since its first release. As far as I remember (but I may be wrong), the reentrance problem was an issue in ObjectWorks (the predecessor of VisualWorks. Closures are really “closed” and don’t share local variables’ state.
You’re right: Smalltalk is widely used in industry. And it’s not only banking stuff. I was member of the leading dev group at AMD where they implemented a major part of the chip production software which controls the machinery to produce computer chips (CPUs). Other projects of mine are web applications built with seaside, a web app dev framework which is available for most Smalltalk dialects.

This sounds like the same “limitation” that Squeak (and its derivatives like Pharo) had until recently – block temp variables were in fact stored in the method context where the block was created. This prevents proper recursive use of blocks as true closures. BUT this has been fixed and these days all (AFAIK) Squeak derivatives and certainly most commercial Smalltalks like VisualWorks do have proper real closures.

Not sure what you mean about more than one instance of the closure. It’s an object, not a class of objects. Would you expect a single object to have a different state each time it’s used, whether it’s used in multiple threads or a single thread?

Coding on Ruby puts the food in my plate. The problem with Ruby is that the syntax for creating blocks is not as nice as Smalltalk and blocks passed to methods require a special syntax and there can be only one per method. There are workarounds but they are ugly.

Care to share workarounds with me. I am having similar thoughts about blocks (only one, and syntax which is inferior to Smalltalk). The thing is I thought Ruby blocks are great (I still think they are), but they seem limited compared to the “origin. I was watching Matz talk on Ruby 2.0 features, there is some talk that after keyword arguments support gets enables it will be easy to support multiple blocks in method calls. (Hash for keyword arguments can get you only so far). Btw. the other improvement in Ruby 2.0 will be traits, which is mixins done right (ofcourse from Smalltalk).

I can’t reply to your answer down… yes I agree ruby version it is ugly. Lambda syntax with -> is helping a bit, but if feels unnatural and perlish :) Smalltalk is pulling it off ok, with multiple blocks support and better block literals, and Clojure is of course right at home with macro chainsaw. I am hoping for things to get better in Ruby 2.0 but I am not sure how much can be done, since Smalltalk is capitalizing on using dot for “end statement” and not method call. And exactly that is getting in a way for Ruby syntax.

My first professional language was lisp – then Smalltalk. It took me about six months or rewiring my brain to really start thinking in Smalltalk. It’s still wired that way, and often causes me problems in languages that are built with special cases instead of a clean, simple, intuitive, class and metaclass semantics.

If they would have just got the team programming part right … We wouldnt have needed Java.

thank you for that simple and convincing text. Exactly this experience of Smalltalk thrilled me many, many year ago. Therefore it became my mother tongue amount the programming languages. And I still don’t know, why it is not that convincing for many people.

where name would be, let’s say, a string. So then you need to implement an equals: for string, which would compare each character. Something you can also implement in Smalltalk. At some point, sooner or later, you are comparing numbers, at that point you have a comparison that it’s not really written in Smalltalk, or it is, but gets compiled, if you go deep enough, to the processor assembly comparison calls. I haven’t actually done the research on this and I’m just supposing, but you could download Squeak and see how deep the rabbit hole goes.

One of my favorite Smalltalk examples of the cool/interesting things you can do when you have first class block closures that are easy to use in literal form, is the Dolphin Smalltalk implementation of do:separatedBy:

I’ve had the good fortune to be exposed to Smalltalk in my teens, but never got any real practice with later.

When you send a message that the receiver does not understand (ie. “when you try to call a method on an object that doesn’t implement that method”) it instead re-sends the message doesNotUnderstand: with a parameter detailing what exactly wasn’t understood. This sounds like an exception, but it’s really just an ordinary message (“method”) inherited from Object, and you can replace it. (The default implementation is to start a debugger or something.)

So I remember an article complaining that some complicated classes might have messages with lots of parameters where it’s easy for a programmer to forget the exact order of keywords, e.g. searchBackwards:step:with:using:interleave:except:foo:bar:. The solution was to redefine doesNotUnderstand (in that class or in Object) to send a new message tryToUnderstand: which would try to permute the keywords (and arguments) so they fit the class :)

Reflection is so trivial here you don’t even notice it as a special concept at all. Many modern industry workhorse languages could pull off similar tricks, but it would be some deep hackery that 90% of professionals couldn’t reproduce without a few hours of trial and error and poring over the docs. In Smalltalk, it was just 6-10 lines of clear, obvious code.

The equals: is hardcoded for simplicity, but we can try to dig a little bit deeper there. What would be want equals: to do? Maybe compare the members. That class has no members but we can imagine it contains a name member variable. Then equals: would be something like:

The first line is just to make sure they are the same class, otherwise, they are different. Then I compare the name and if that is equal, I consider the object equal. Now we pushed the problem into defining equals: for classes and strings. For classes maybe we compare a global id of the class and for strings each of the characters. We keep pushing the problem until we reach the comparison of a single integer, which is something the microprocessor or the virtual machine implements. It would be interesting to see how it looks like on Squeak, but I haven’t searched for it.

The important part though, is that even if at some point we hit some magic, we are talking about equals:, about implementing the comparison between two things, not about implementing if. If is done, implemented and reusable. And this is how it’s done in Smalltalk itself, except that the method is ifTrue:ifFalse: and the comparison is == if I’m not mistaken (I don’t use Smalltalk daily).

Sebastian, the equals: method was not what Pablo was trying to show – you can implement it either way you like, he just hardcoded it to true so that he could carry on with his implementation of if-else. The trick in Smalltalk is that everything is an object (even booleans) and we have two different instances of two different subclasses (these classes are called True and False) that can respond to the same messages but do different things (=polymorphism). Thus, we solved the if-else control structure using booleans as objects, polymorphism and having true closures (blocks).