Neither Lisp nor C

Posted on June 7, 2015

I will start off with two bold claims. First, I don’t like C. (With that, half of everyone thinks I’m crazy.) Second, I don’t like Lisp. (Now the other half of everyone agrees.)

Lisp and C are both very powerful languages. The power of either is nearly unbridled, though it lies in different areas.

The strength of Lisp lies in the ability to manipulate the raw syntax tree at will, giving you the ability to reshape the language into anything you see fit. It’s all very abstract. Lisp is about ideas, not about details of implementation. It places almost no restrictions on what you can do. It’s a little bit hard to explain the power of Lisp; it’s more a thing that must be experienced first-hand.

Details of implementation are, in a sense, what C is all about. For a low-level language, it has a surprising amount of high-level power. You can pass pointers to functions around, you can modify the text of the program with macros, you can even create new functions at runtime provided you know the assembly for the target architecture. And it is here that C shows its true colors: it’s about interacting with the real system. In C, you work with real1 addresses in memory, real pointers, and have direct access to everything. You can even read the instructions making up a function in a compiled program. The incredible power it gives you over the actual machine is why is it still the lingua franca of operating systems.

There are, on the other end of a different spectrum, languages that are called “opinionated” when we are being kind (but might be more correctly though of as bossy). Java and Go come to mind. Java demands that everything be an Object. Go levies a frequent tax of an extra “if” statement to check if the return value included an error. Of the two, Go is the greater stickler, but that’s not important right now. These languages place many restrictions on what you can do. Some of them are quite worthwhile, preventing the compilation of far more bugs than of reasonable programs. Others, however, are simply painful exercises in helping or pleasing the compiler.

There are other languages like Haskell which are also restrictive – even more so than Java or Go – yet manage to forge something new out of the restrictions. Haskell has far stronger type checking and guarantees than nearly any other language. Under normal conditions, all variables and values are immutable. Code isn’t even allowed to (directly) perform IO! And out of those restrictions comes a succinct, expressive, powerful language. Many programs can be shorter in Haskell than even Python. It’s a language that would not be possible without the restrictions. It can do away with certain cases in logic because the language can guarantee that they will never happen (for example, checking if a value is null). Boilerplate can be left for the compiler to figure out because is can figure it out. A new kind of freedom is built by the power afforded with the restrictions.

And this is what I don’t like about C and what I don’t like about Lisp. In those languages, the compiler does your bidding, no matter how complex or far fetched. It give you the power to do whatever you ask for. But it doesn’t talk back. It doesn’t work with you, it doesn’t help you avoid simple mistakes (never mind complex ones), it doesn’t help shape the program. It just blindly gives you power with no finesse.

The two of them, C and Lisp, are a hand-built pickup truck and a formula one car. Both very powerful, both do just what you want, and both are a certain kind of dangerous. Both require knowing every last detail and paying 100% attention or things fall apart and spin out of control.

(Java is the minivan. It’s not powerful or fun, but at least it’s pretty practical and safe. Let’s bundle the kids up in it as they learn their first language, because that will ensure that nothing too bad will happen.)

What I want is a language that drives like a German luxury car. Let’s say an A7. It’s very powerful, but that’s almost not the point. When you turn the wheel, the car goes precisely where you want. It’s not a manual process that requires strength from you, nor a mushy process where you aren’t quite sure where the car will go, it’s a easy, crisp, precise turn. You could hit a dime in the road going at 100 miles an hour. It may give you this precision using a fancy suspension and electronic stability control and a thousand other tricks, but you don’t have to think about that: The steering always works perfectly. At the end of the day, any luxury car worth it’s road salt is going to be comfortable for the long haul. It will always get you there quickly, in comfort and style.

  1. Ignoring the detail of virtual memory.