Always outnumbered, never outgunned: Why I love Smalltalk.
Some programming languages are beautiful and some aren’t.
Oooo. Dafydd’s going to insult programming languages. Let’s see if he’s going to insult yours… ;-)
Some beautiful ones:
Some really ugly ones:
- Visual Basic (okay, I admit I only saw it before the .Net era)
So what’s the difference?
The beautiful ones share these traits:
- They’re minimal
- They have a tiny set of core principles from which everything is built.
- Understanding that core set of principles may take some time, but when you’ve mastered them you can change just about anything in the environment around to help with your software.
It took me a while to see what was going on in Smalltalk but I think I’ve got it down to the only two things you can do in it:
- assign references to an object into a variable
- send messages to objects through an object reference
Everything that happens comes down to that. Making new classes, adding methods, changing methods, running new threads, saving code, compiling, really those two things are all you can do and everything is built out of it.
When you’ve got a tiny set of principles that are used to construct your entire little software world things work together very well. In a language that’s a mishmash of inconsistent principles, features and syntax hacks from all over the place you might find that you need to do three things and that you use three different techniques to do them. Then, later you find that they don’t fit together quite right and you have to write lots of bridging code. This code might well be inefficient but it’s almost certain to be really ugly. That’s the price of inconsistency: really bad design.
One of the most beautiful pieces of code I’ve seen is the construction and use of meta-interpreters in prolog. Instead of just answering a true/false question you can pretty much redefine whatever part of the evaluation you want. You could add in fuzzy logic, or three-valued logic, or you could collect the proof tree explaining how you got to the answer. You can do all this and you can do it without changing the logic progam you’re actually going to evaluate with it Now in Java they’ve deliberately locked down many parts of the system so you can’t have that level of influence on how they work mostly for security reasons. Trying to change aspects of the language within the language is something that Sun seemed to have deliberately designed out of Java. They wanted uniformity, security and a language where legions of people could write safe, mobile code.
What the “ugly” programming languaes have in common is that they’re a mishmash of conflicting features and ideas and that the “seams” between the conflicting ideas mean multiple, different ways things could be done, and lots of ugly glue code. I remember somebody explaining to me that they were having problems handling a Groovy parse tree because of “special cases”. They suggested actually adding other special cases to handle the problems they were experiencing… and I began to get that “out of body experience” I get when I’m standing next to a “complexity magnet”. To be clear:
“Guys - Don’t slap in more random features and special cases to fix problems. The real source of the problem is that what you have doesn’t hang together consistently. Trying to force-fit it with power tools isn’t going to help. It’s the source of the problem. In fact if it continues there’s a danger the language will die under it’s own weight and complexity.”
Groovy is a practical and useful language but it has the kind of “semantic bling” that only Ali G could love.
This amazing “magic trick” they showed us in college with prolog meta-interpreters is possible because of deliberate limits placed on what you can do with prolog. Because there’s only a limited number of things you can do in the language and a limited number of ways that things can be assembled, it’s possible to get an intellectual handle on the meaning of the programs.
With languages like Perl and C++, it’s difficult enough to get an independent language implementation to yield the expected behaviour, let alone get enough of an intellectual handle to reason about changing it or compiling it into something else. A language made from a few simple, powerful rules gives you the power to write programs that can manipulate programs. Every little “special case” in a language might not impact the programmer that much - but when you’re metaprogramming you’re thinking about the set of all possible things that could happen at a particular point. An ugly, language design burp means that set of all possible things that could happen is probably bigger - perhaps multiple times bigger.
Right now, look at the difficulties getting multiple versions of Ruby to behave consistently - and contrast that with the work that happened with the amazing self-bootstrapping Smalltalk generated from Smalltalk work done in Squeak. To go a step further: The Squeak Smalltalk bootstrapping mechanism “just” transforms a Smalltalk interpreter written in the Slang subset of Smalltalk to C. An even neater trick is the idea of Lisp macros: Of course the Lisp syntax looks freaky and limiting. It’s not just a programming language grammar, it’s also a data format so programs can transform themselves.
Amazing “DNA-like quality”
That’s what Paul Graham said that Lisp has. I can’t help notice the fact that Alan Kay one of the original pioneers of the Smalltalk language used to be a molecular biologist. Nature has a level of resilience, agility and scale we just don’t see in any of our systems so maybe this kind of “beauty” really matters.