Wednesday, 31 December 2014

CljOS - Objectifying Clojure

The venerable master Qc Na was walking with his student, Anton. 
Hoping to prompt the master into a discussion, Anton said 
"Master, I have heard that objects are a very good thing - is this true?" 
Qc Na looked pityingly at his student and replied, 
"Foolish pupil - objects are merely a poor man's closures."

Chastised, Anton took his leave from his master and returned to his cell, 
intent on studying closures. He carefully read the entire 
"Lambda: The Ultimate..." series of papers and its cousins, 
and implemented a small Scheme interpreter with a closure-based object system. 
He learned much, and looked forward to informing his master of his progress.

On his next walk with Qc Na, Anton attempted to impress his master by saying 
"Master, I have diligently studied the matter, and now understand that 
objects are truly a poor man's closures." 
Qc Na responded by hitting Anton with his stick, saying 
"When will you learn? Closures are a poor man's object."

At that moment, Anton became enlightened.

~ * ~
When I first started learning Clojure (and Lisp in general), I was extremely skeptical, and the primary source of skepticism was what I had been reading about functions. 

Functions in Lisp were described as beings of great power and flexibility, especially if they could "close over" their environment. Having been exposed only to what are called functions in C and static-methods in Java, I could not even begin to imagine how they could possibly be as powerful as objects.

The first step to realizing the awesomeness of Lisp functions was using higher-order functions. The whole concept of Java Interfaces that I had loved so much flew right out the window. This approach was simpler, more intuitive, and actually easier to write/read/modify. Just compare examples of sort-by to how you would do something similar in Java.

Now, I had written a game engine in Java (Kilvish), and was thinking of porting it to Clojure. I had originally intended to write idiomatic Clojure, but that would require a complete redesign of my Java code. This is when I had a scary idea.
"Lisp has jokingly been called "the most intelligent way to misuse a computer". I think that description is a great compliment because it transmits the full flavor of liberation: it has assisted a number of our most gifted fellow humans in thinking previously impossible thoughts."

(Edsger Dijkstra, CACM, 15:10)
I realized that I could add an Object System to Clojure, and reuse the same structure as my Java code. And though this sounds like a big project in itself, I was able to achieve this in less than a hundred lines of idiomatic, documented code! The result was CljOS.

After this, it was business as usual, and I ended up with a small game engine that I call Bakait.

CljOS is NOT a re-implementation of the Java OOP system, by the way. Much like the rest of Clojure, it is closer to what Python provides. CljOS does not 'hide' any data, for example. Being written in Clojure, it is also thread-safe.

Another *BIG* difference from traditional OO is the inheriting of class-variables as well as methods.  This is not a problem because just entering a class name at the REPL shows the entire structure of the class- every property, method, and the entire class hierarchy that it is a part of.

Anyways, Rich Hickey (the creator and BDFL of Clojure) hates objects and has good reasons for it. I don't use CljOS myself when writing Clojure, and generally wouldn't recommend anyone else to use it. But its existence reminds me of the power I wield being a Lisp programmer. Although Rich has (good) opinions on how Clojure should be used, the language itself is extremely malleable.

In short- Clojure doesn't tell me how to write my code, I tell it how to execute it.

No comments:

Post a Comment