Was Alan Kay wrong? And why does that matter?

Sometimes people say extreme things, such as “Functional programming isn’t truly possible without referential transparency.” Whether we agree or disagree, the act of looking at an extreme statement and analyzing the ways in which it is right, the ways in which is wrong but practical as an abstraction, and the ways in which it is fundamentally wrong is a very, very useful exercise.

Here’s a quote that appears in a book I’m writing:

OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. There are possibly other systems in which this is possible, but I’m not aware of them.—Dr. Alan Kay on the Meaning of “Object-Oriented Programming”

Ignoring the obvious (Alan Kay can’t be wrong about what a word means to him personally), people have been arguing for decades whether messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things can be done in languages other than Smalltalk and Lisp.

It’s worthwhile to question whether Alan Kay was wrong, because it forces us to become very specific about some very important ideas:

What is “Messaging?” Is forcibly invoking a function the same thing as sending a message? What is “Local retention?” What is “Protection and hiding of state-process?” How absolute must it be to qualify? What is “Extreme late-binding?” How extreme is extreme?

greenspunning

Greenpun’s Tenth Rule suggests that “Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.” One interpretation of this rule is that all non-trivial programs require non-trivial semantics for representing behaviour in the problem-domain, and if your language doesn’t supply it, you will need to build support for non-trivial semantics into your program just so you can represent them in your problem-domain.

Building new semantics on top of a language that lacks them is often called greenspunning after this rule, although it rarely involves FORTRAN, C, or Lisp. Let’s take JavaScript as an example. It looks kind-of OO if you tilt your head sideways. But, are you really doing “messaging” if you don’t have something like a method_missing handler that lets an object decide extremely late whether and how it responds to a message?

Of course, we can “greenspun” method_missing into JavaScript by eschewing method function invocation and doing all messaging with a send function. If we do that, are we programming in JavaScript? Or in another language that we built in JavaScript?

The same goes for generic functions, meta-object protocols, and all sorts of things. If we have to greenspun OO semantics on top of a language that doesn’t natively support those semantics, are we doing OO in that language? Or in spite of that language?

I’m not going to say what I think about whether JavaScript is an OO language in Dr. Kay’s sense, only that if you have this debate with an open mind, there’s something important to be learned about your favourite language and about OOP.

making better decisions

Ok, so we’ve debated a subject like “Is JavaScript an OO language.” We’ve learned something. Now what?

Erik Naggum once wrote something intriguing in the middle of a flame war:

Basically XML is just another way of writing S-expr or Trees or whatever you want to call it.

They are not identical. The aspects you are willing to ignore are more important than the aspects you are willing to accept.

So after our debate, we wind up with an understanding of the ways in which a language like JavaScript fits the definition of “OOP,” and an understanding of the ways in which it doesn’t fit. Let’s presume we aren’t about to put JavaScript down and pick up Common Lisp.

If we are to carry on doing OOP, we have to take all the things JavaScript doesn’t do and put them into two piles:

The things we are going to ignore because they aren’t important to us. The things we are going to greenspun because they are important to us.

It can be enormously valuable to make this decision explicitly, to be very certain about whether the things we’re ignoring aren’t important to us.

We can start by designing our program as if our language of choice supported all of the semantics we find in languages like Common Lisp: before- and after- handlers for methods, generic functions, pattern matching, multiple inheritance, everything.

Then make a cost-return calculation for each feature we think would be useful as part of our initial design. Now, it’s true that these decisions will get made eventually, if only by default. But without falling into the “Big Design Up Front” trap, there is a lot of value in making these kinds of decisions together, in each other’s context.

It’s like budgeting. If I say, “Is a Retina MacBook Pro worth CAD $1,299?”, that question is kind of abstract. If I say, “You have four thousand dollars to equip your home office, will you include a $1,299 Retina MacBook Pro?”, you are going to have a more meaningful answer when you’re considering all the other things you need to buy and how they fit together to make a complete home office. For one thing, if you home office includes a dedicated desk, maybe you want a 27” iMac. Or is there budget for an external display to use when you’re at home?

The same is true of greenspunning new semantics. Are generic functions worth the trouble? What about before- and after- methods? Most people make decisions like this on-the-fly as they’re programming, or in the abstract when reading a post on Hacker News.

That isn’t the same thing as making a decision in the context of a software design. For example, if we look at before- and after- methods, I have personally written three different libraries for greenspunning this feature into JavaScript: allong.es, Method Combinators, and YouAreDaChef.

Presuming we want to use before- and after- methods, which one should we use?

allong.es is a medium-sized library that supports all kinds of functional combinators. It’s a good choice if we embrace the idea of composing and decorating functions in the current design, and we think of before- and after- as decorations. Method Combinators is a small library that does this one job–before-, after-, around-, and guard- method combinators–and nothing more. YouAreDaChef is a much deeper approach that greenspuns multiple dispatch on top of JavaScript prototype chains. It’s ideal if we are very committed to modeling entities with class hierarchies.

To make a decision about which library to use, we need to think about the project as a whole. We also need to think about the other decisions we are making. For example, if we go with YouAreDaChef, that may create conflicts with other libraries or approaches that introduce new ways of inheriting methods. Then again, it may make some of the other things we want to do easier.

back to basics

This brings us back to the original point, Alan Kay’s quote:

OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. There are possibly other systems in which this is possible, but I’m not aware of them.—Dr. Alan Kay on the Meaning of “Object-Oriented Programming”

It is not important whether, in 2013, what somebody said back in 2003 is still right, or was ever right. What matters is how thinking about the statement provokes us to improve the way we think about what we’re doing today.

When we question extreme statements with an open mind, we are equipped to make intentional choices about how much of this ideal OO we wish to demand of our tools, how much we wish to “greenspun” deliberately on top of our tools, and how much we wish to intentionally ignore.

(discuss)

p.s. Did I mention that I’m writing a new book? I did? Ok then, nevermind.