Seems like I do have a favorite programming language after all. The sad part is that is doesn’t exist; it’s more of a what-could-have-been type of language.
Maybe it’s because I’ve passed the magical border of being over-thirty-and-married-with-kids, maybe it’s some kind of mid-life get-off-my-lawn stuff. Who knows. But let’s put those thoughts aside and take a look at the advancements made in the field of programming in the last 10, 20, 30… years. While on the surface, it does look like there’s been a ton of new stuff, if you dig a little deeper, it’s sad. Not kind-a, but really, really sad.
Let’s begin with a little side-step (don’t worry, I’ll say the “L word” soon enough). What is it that made Unix and all its copycat systems so popular? Textual data, and what you can do with it. Nearly every program in a Unix base system install either creates some textual output or is a filter, that is, it takes textual data from somewhere, does something with it, and outputs more text. You can ask one program for some info, put (“pipe”) that info into another program, then yet another, and after some piping, you get the data you really wanted. Want an example? Show me a list of all “using” directives in a C# project, sorted alphabetically! Easy as pie:
ls *.cs | xargs cat | grep using | sort | uniq
What we do here is ask the
ls command for a list of C# source files, then pipe that list into the
xargs command, which in turn asks the
cat program to list the contents of those files, then the
grep program finds all using directives. Then that list is sorted with the
sort command, and finally the
uniq program removes all duplicates.
I can hear thousands of Unix guys screaming at me right now. Yes, I know there are more elegant solutions to this problem. There is always more than one way to do it. But bear with me – this is just an example to show that the Unix shell is basically a functional programming language. The interface to the OS can be used just to start programs (“call functions”) with some set of parameters, but also to combine them into new, more powerful ones (functional composition). And THAT, folks, is what made (and still makes) Unix so immensely powerful.
With all those parentheses in the last paragraph I take it you can already guess where this is leading, but we are not in LISP land yet. Let’s take another side step and have a look at the Oberon system. Born somewhere in the middle of the 80s, it was waaaaay ahead of its times. Still is, in quite a few ways. One of the most interesting features, apart from its staggering simplicity, is that every little bit of text, even the title of a window or a menu item, can be used as a command to be executed. Not just in an “Oog select menu item” context, but in a “call the compiler on that window title and run the resulting program” way. Cool stuff. I’m not entirely sure how such functionality could be useful (I’m just a Blub programmer after all, just like everyone else), but it’s cool. And not only the OS and the compiler, but simply everything in Oberon, the system, was written in Oberon, the programming language, designed for a special machine to run it on, but still extremely easy to port to other machines. Oberon’s file system had Garbage Collection and could be used directly as an Object Database. Not bad for a system conceived in the middle of the 80s, eh?
The next logical step to take in our little excursion is the one that, ironically, takes us even further back in time. LISP machines were computers designed specifically to implement a LISP system, and LISP was not only the primary programming language, but the whole operating system AND the shell, all in one single, coherent piece. Like the Unix shell, the LISP REPL was not only a way to call functions (start programs) with some parameters, but it could be used to compose more powerful functions, too. Just that is wasn’t simple textual data that was “piped” from one function to another, but strongly typed, structured data. Both Unix and the LISP machine evolved in parallel, at the same time. As we all know (right?), Unix followed the “Worse Is Better Approach”, focusing on getting out something that works as quickly as possible, while LISP used the “MIT Approach”, getting things right, even if it takes a little longer. The cheaper Unix workstations and AI winter brought an end to the success story that LISP could have become, had it not been caught in the vortex that swallowed AI projects all around the globe.
When computers became viable for the masses, the early Home Computers had little to offer: Cheap, mass market compatible, but limited to 8 or 16 bits of computing power, with the operating system coupled to puny BASIC interpreters. Sure, looking at the Commodore 64 BASIC disassembly, you can see what marvelous tricks the creators of these interpreters had to use to cram their systems into a few kilobytes of memory and make the computers as useful as possible. But imagine, say, a Commodore 64 running a LISP interpreter a second after switching it on. The possibilities!
And that is what makes me sad. All that neat stuff we’re being presented with, right now, as “totally new”, is just old stuff re-discovered and warmed up. Wirth, the genius behind Oberon, used P-Code (Slim Binaries, think Java bytecode, .NET IL) before it was cool. He used “delayed code emitters”, that have now, decades later, suddenly become something totally new in the Java and .NET JITters. The Unix shell and the functional programming it allowed have been re-re-re-released in the MS PowerShell, with some OOP thrown in. It’s LISP machines all over again. The new, fancy debugging abilities found in the newer Visual Studio versions make a seasoned LISP programmer weep. Not in awe, but with nostalgia. Hey, now .NET can even create and compile code on the fly with Expression Trees! Welcome to the 70s.
Don’t get me wrong. There have been huge advancements in the past, especially when it comes to Software Engineering. But imagine what could have been. Imagine a world where the Star or the Lisa had been more successful. Where LISP machines, or at least their paradigms, had stayed with us, instead of becoming some historical side note to be rediscovered now. Once again.
So that’s my favorite programming language: What a mixture of LISP, the Unix shell and Oberon and all the other really powerful inventions that went the way of the Dodo could have become. Yes, Common Lisp is pretty close to that, sporting not only one of the best OOP systems there is, but dynamic re-compilation, Slim Binaries (FASL files), Just In Time Compilation, deterministic finalizers and much, much more. But Common Lisp suffers from lots of bipolar programmers, bizarre package and library names, and can anyone find a GUI library that actually works?
Because that would be, like, really neat.