Building a true object-oriented system for Common Lisp

While the title of this post may be seen as inflammatory, allow me to elaborate before dashing off to the comment link and turning your flamethrower loose.

As you have probably been taught, Dr. Alan Kay coined the term "object oriented" (OO). His term, his rules (Which can be found here: http://www.purl.org/stefan_ram/pub/doc_kay_oop_en). The Common Lisp Object System (CLOS) does not fit the bill to be called object oriented, although it still arrives at many of the benefits of object-oriented principle (and perhaps more -- I will expound on this later). But as Dr. Kay mentions in the above link, OO can be done in Lisp.

I have been exploring programming languages a great deal as of late. One language in particular, Erlang, has caught my attention because of its much hyped nothing-is-shared model of concurrency. Erlang accomplishes scalability by breaking tasks into many lightweight processes that communicate with each other in the form of messages. (Hmm. Where have I seen that before?) There was something very OO looking about some of the code samples I saw. Only instead of method names being "invoked" on an object, a process listens for messages of different types and those message types are represented by "atoms", which are essentially strings that contain some meaning to the program. Communication between processes in Erlang fits with Dr. Kay's requirements for an OO language (messaging, late binding, etc). It also fits the Actor model.

It can be quite confusing to distinguish between the Actor model and that of OO programming. The reason? (And this will likely be a point of some dispute.) There isn't really any difference. The term "Actor model", I believe, just had to be invented because the term "object oriented" had come to represent something other than the original meaning. OO programming has now become synonymous with stack-based models where messages are passed up and down the stack and "messages" are really just function calls conceptualized as messages. Actors on the other hand are discrete (messages and responses don't traverse a call stack) and are therefore inherently concurrent. Erlang processes and web services are good examples of the Actor model.

Now back to CL. CLOS uses multi-methods instead of message passing, so it is not strictly OO. However, as promised earlier, I'm going to stroke the CL users a little bit here and propose that perhaps the CLOS model is more appropriate to be called "object oriented" than Dr. Kay's model. Why? Because OO programming is (supposed to be) all about the encapsulation of behaviors, and objects don't do anything. But functions do.

What do you mean, "An object can't do anything"? Well, in real life, an object (I think of a rock or a piece of wood) does not do anything. A rock cannot skip itself, change its location, size, or color, or tell you any of these things about itself if you send it a message. A rock is simply a rock. If you think in procedural terms, it would be a data structure.

A data structure? Wha? I thought that "everything is an object?" OO languages assign a sort of anthropomorphic view to objects (Objects are people too) which makes perfect sense if you look at the design principles behind Smalltalk (the language Dr. Kay invented to go along with the term). One of the major design goals was to create a human interface with the machine, to allow the programmer to think in an (arguably) more human way.

Along those lines (thinking like a human), I like the term Actor better than Object because it can be explained in a way that makes sense. A rock cannot tell you anything about itself. However, an actor portraying a rock can. (I'm not a rock. I just play one on TV.) This way, everything can be an actor and the model stays coherent. There is no data, only actors that portray it. (Again, refer to Dr. Kay's letter above and where he talks about dataless programming.)

This makes sense to me as I often equate programming language models to models of the universe. But the question remains how to best model the universe. What is the essential building block of the universe? Is there one?

So what is the building block of a program? An object? And what about not only modeling what an object can do but what can be done to it? What rules? What forces apply?

Enter functions. In CLOS, a function (or group of functions called multi-methods) defines a behavior for an object. And these behaviors govern object interactions. Just as a rock has no knowledge of everything that can be done to it, the behaviors do not belong explicitly to the rock, but rather to the context in which the rock is to be used.

And this model is more coherent for "objects" (as I described them earlier). But for our anthropomorphic figures, objects that DO, it makes more sense to just ask them (as in the messaging model).

Most modern programming languages have lost coherency in their model. So when I ask what the building block of a program is, it's not simply rhetoric. The answer will, of course, vary by model, but then is it even possible to introduce a model where there is a single coherent answer? Well, of course it is possible. But perhaps a better question should be, is it practical? Is it a viable way to model our universe?

The question came to me when I realized that an object could be implemented as a function and vise versa, so it's sort of a chicken-and-egg problem.

In some languages (one of them is CL), a function may be curried with a particular parameter or live within an enclosing scope. These functions are essentially just objects as we know them. Here's a short example:

(let* ((privateVar 2)
(methodDictionary
`((set . ,(lambda (x) (setf privateVar x)))
(+ . ,(lambda (x) (+ x privateVar)))
(- . ,(lambda (x) (- x privateVar))))))
(defun simple-object (methodName &rest args)
(apply (cdr (assoc methodName methodDictionary)) args)))

(simple-object '+ 2) ; equals 4
(simple-object 'set 40)
(simple-object '+ 2) ; equals 42

A whole object system can be created using such closures. In fact, that's exactly what I've done. It may not have been the most practical exercise. (I'm certainly not advocating using it over CLOS.) But for someone interested in language design, as I am, you may find it enlightening. It is prototype based, and state is kept private. You can find it here or on Wikipedia as YACLOS, so feel free to improve on the code if you are so inclined.

3 comments :: Building a true object-oriented system for Common Lisp

  1. I like it. Lexical closures. I like the idea of creating a function to access the object. You might want to check out my blog.

  2. @gutzoft I would love to. Where is it?

  3. Sorry about that.

    http://uglylispcode.wordpress.com

Post a Comment