Clojure Gazette 176: The Ultimate Abstraction

Free Beginner Workshop

From OO to Clojure Workshop!

Watch my free workshop to help you learn Clojure faster and shift your paradigm to functional.


The Ultimate Abstraction
Clojure Gazette
Issue 176 - June 6, 2016

Please consider advertising in the Gazette.


Hi Clojurists,

Let me recap the little thought experiment we have been setting out. We are exploring the idea that smaller abstractions are, all other things being equal, less risky than large abstractions. And we also saw that, at least in an oversimplified model of code, smaller abstractions can reduce our total code size, despite their overhead. But what about runtime overhead?

In general, calling an abstraction has a runtime cost. Each abstraction is an indirection that can compile to more code than the inline (indirection-free) solution. When functions were first introduced in programming languages, you'd only want to use them rarely. Yes, computers were a lot slower back then. But the main reason not to use them was that compilers were not very good. In order to do a function call, the compiler generated code so save all of the registers, some memory, save the arguments, save the return point, then jump to the start of the function. It was a ton of work just to call a function.

Languages that used a lot of functions, like Lisp, were considered slow. Other languages used JMP instructions (GOTOs) instead. It wasn't until Lambda, the Ultimate GOTO, a paper by Guy Steele and Gerald Sussman, did compiler writers catch on. It turns out that many function calls can be compiled into a single JMP. And many more can be compiled into much tighter code than what was normally done. Those compiler techniques made the early Scheme implementations super fast. They used lots of small functions because they were easier to work with. And those techniques are in good compilers everywhere now.

Lambdas turn out to be a really elegant abstraction. But what about all of those inelegant abstractions? What about languages written quickly, without regard to performance or compiler knowledge? Can they be fast, too? Well, all I have to say is "JavaScript is fast now". Time and again, with enough experimentation and brainpower, even the worst languages can be made fast. Google and Apple and Mozilla competed for the fastest JavaScript engine. They invested millions, if not billions, in the effort. There was a time when people recommended not using too many functions in JavaScript. But now you can write 3D games in it, all with callbacks. PHP is even fast now if you use the HipHop Virtual Machine (HHVM), developed by Facebook. Facebook runs a lot of servers and it's worth a lot of money to make PHP fast.

The runtime costs of abstractions are what keep language implementors up at night. Joe Armstrong, one of the inventors of Erlang, talks about the importance of keeping the memory and runtime overhead of processes and message sends low. Alan Kay talks about how Smalltalk kept the memory overhead of each object down to a single pointer. And one of Rust's "pillars" is "Abstraction without overhead". Seriously, people are on this. They're working very hard to make it so we can write tiny abstractions.

The lesson in all of this is that when designing a language, we should just pick the most powerful abstraction we can find. Even if the overhead is too high now, with time we can find a way to reduce it. However, it is clear that more robust abstractions are easier to make cheap. Fast function calls are easier to implement than fast dynamic, mutable objects. But if that's what you want, just throw more grad students at the problem.

From the software developer's point of view, it means you should pick a language with fast abstractions. If you're worried about the overhead of function calls or objects or whatever in your current language, that is a good reason to switch. Your language is keeping you from doing your job. If your job is building abstractions, would you really want to use something that doesn't help you abstract more? We've talked about the code size and runtime overhead. But are there more costs that we haven't considered? We'll look at that next time.

Rock on!
Eric Normand <eric@lispcast.com>

PS Want to get this in your email? Subscribe!
PPS Want to advertise to smart and talented Clojure devs? PPPS Read the Lambda the Ultimate papers.