Better Objective-C through Clojure Philosophy

EDIT June 2, 2014: The TERecord implementation described here is not how the current TERecord implementation works. I updated the README on GitHub to show how it currently works.

Ever since discovering Lisp, I’ve felt an almost… loathing for other languages. They make things too complicated. You feel that other languages encourage code that ends up ugly, verbose.. inelegant. This feeling is so well known, it even has a name, the “The Lisp Snob“. Well, I’m quite sorry, but I think it’s too late for me, I’ve succumbed to the snobbery!

It’s possible, however, to bring over some of the ideas from the Land of Lisp to other languages. Indeed this is essentially what has been happening for the past several decades, people just call it something different (“a new language”, or “new features”). Today, I’d like to show what happens when you bring one such idea to Objective-C:

It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures.

Unfortunately, the example code that created the screenshot above suffers from a very common programming paradigm called Object Oriented Programming (OOP). The OOP paradigm has dominated Earth’s developers for the past several decades. I used to follow (and teach!) it, but after learning Clojure, I’ve changed my mind. I now agree with the Alex Rozanski quote above and Rich Hickey: it is better to have a small number of core data structures (preferably immutable) that are manipulated by hundreds of functions.

For this post, I will focus on just one of the many benefits of dropping the OOP perspective: code brevity.

The chief source responsible for the screenshot above is copied below. My point here isn’t to ask you to actually read through all of it, just note its size.

By using “special” dictionaries, we can greatly reduce code size, and enhance flexibility

Clojure has the concept of “records”. These are basically “special dictionaries” (AKA maps). Clojure uses maps/dictionaries all over the place, because it realizes that it’s not only not necessary to create a new class for every type of data you have, but it’s counter-productive.

Today I spent some time adapting the idea of Clojure’s records into its Objective-C equivalent simply through the creation of categories on the NSDictionary and NSMutableDictionary classes. The result is that I was able to reproduce the screenshot above with the following code (equivalent sections to the ones above):

Not only is the code above more flexible and significantly shorter, but it’s clearer as well! You can practically visualize the GUI’s structure from the code itself!

The rest of the code (related to the delegate methods) is essentially equivalent, except it’s again, shorter.

“Magic” Dictionaries with Properties!

Dictionaries are created using the _MD and _D macros (for creating mutable and immutable dictionaries, respectively). These are plain old standard Foundation dictionaries. They can be saved to the hard disk, read back, key-value coded, etc. The reason for the macros is code brevity and because they use a new dictionaryWithKeysAndObjects: method that’s added to all dictionaries through the categories (I have no idea why Apple’s engineers throught it would be better to have values come before keys as with dictionaryWithObjectsAndKeys:…).

Next, let’s have a look at how dictionary values are manipulated and obtained. Most semi-intelligent languages have a map literals and simple syntax for fetching and setting map key/value pairs. Objective-C has no such intelligence imparted to it. However, it does have the very nifty forwardInvocation: mechanism. By combining forwardInvocation: with Objective-C protocols and properties, it’s possible to create “Objective-C records”.

@Jeff: Yes, thanks for the link, I do know about Nu, and I am very happy that it exists, but the reason I don’t use it though is because it doesn’t compile down to binary (as far as I heard last), and for some projects I prefer they do.

First, we could have “cleaned up” the first block of code almost as easily by adding a bunch of macros to it. Eliminate the second version’s magic macros for _MD, NSARY, and NSIMG, and the code starts to become equally dense.

Second, and more to the point, object-oriented programming is about combining data *with* it’s associated functionality.

SourceListItem fails this definition, in that it encodes no object behaviors whatsoever. All we have is — essentially — a bare bones struct with accessors and nothing else.

Refactoring the SourceListItem init method to take an icon image name and not an image could have cleaned up a full third of the list building code.

Implementing an addChildWithName: … method would have cleaned up another third.

And that’s not even counting polymorphic functionality we could add to specific types on the rendering side of the equation.

I see your point regarding dictionaries, but comparing a marco-laden special case to code that exemplifies bad OOP practice in the first place…

Second, and more to the point, object-oriented programming is about combining data *with* it’s associated functionality.

SourceListItem fails this definition, in that it encodes no object behaviors whatsoever. All we have is — essentially — a bare bones struct with accessors and nothing else.

That was… exactly the point. I was making the case against “combining data with its associated functionality”. I did not attempt to make the full argument against it, for that feel free to look into Clojure and some of Rich Hickey’s talks (and there are plenty of others who go into it in more depth as well).

@Christopher: thanks for the link! I had a look over it but it’s not quite what I’m looking for (I’m also not a huge fan of Common Lisp). My wish would be for something along the lines of Clojure for Cocoa, and preferably backed by Apple. Probably won’t ever happen.

Which is how Clojure gets around OOP polymorphism… by duplicating polymorhpism. In effect, Clojure eliminates a polymorphic class hierachy with classes and methods, by implementing a boatload of data-driven dispatch methods that jump to a bunch of specially-named methods distributed throughout your code. (One of the things that OOP tries to avoid.)

SourceListItem, above, would have benefited greatly from subclassing and defining associated functionality for PlayListItem and PlayListGroup. And that, in turn, would have simplified the list building code greatly.

But the developer stopped before that point, allowing you to setup a nice little strawman that could be knocked down in order to show Clojure’s “superiority”.

With smarter objects, the list building code is MUCH shorter, yes? No need to pass in icons, as each class already knows which icon it’s supposed to display. For many, no need to pass in titles, which should be loaded from internationalization strings anyway.

And no macros or oddball syntax to trip up new developers who have no clue as to how your Clojure add-on works. Just the classic OO design methodology… that they already know.

>Which is how Clojure gets around OOP polymorphism… by duplicating polymorhpism. In effect, Clojure eliminates a polymorphic class hierachy with classes and methods, by implementing a boatload of data-driven dispatch methods that jump to a bunch of

Clojure does not “get Around polymorphism it dilivers it A la Carte when you need it, you don’t have to carry it around all the time. You can have a any function for dispatch witch is much MUCH more powerful that your singel dispatch OO (bad C++ style OO) has (if you want your single dispatch just provide “type” as a function). The thing you talk about is called Multimethods and its a very powerful feature that provides multible dispatch and solves the expression-problem in away that is imposible with Java/C++.

What does “implementing a boatload of Data-driven dispatch methods”. Clojure implements nothing you can just provide a function an it can be driven by whatevery you want. What do you mean by Data-driven on what else would you dispatch you class hirarchy is data too.

If you really want to have a hirarchy you can implement one clojure provieds this. You can even implement multible hirarchies.

A little extra information: Apple funded dylan and it should have become THE langauge for programming on the apple but back when the had money problems the obandend it. With a little more luck on the dylan side you would programm dylan today and not Objectiv C.

Alsow look at the CLOS (probebly the most powerful object system ever)

@Michael: That’s definitely an improvement, but (1) please show the equivalent code, you left out several files (one for each of those classes). (2) If you view OOP to be the superior approach, fine, stick with it, do what works best for you. If you haven’t actually given Clojure a serious try though, I recommend it, you might change your mind (as I did).

Objective-C is not a “clone” of C++. Both languages grew up during the same period, and ended up branching out into their own domains. C++ went down the rabbit hole with the STL and the language’s penchant for allowing you to overload anything and everything.

Objective-C, OTOH, is really an attempt to clone Smalltalk’s object and message passing model onto C. Both choose to build off the existing C compilers of the day, much as Clojure builds off existing JVMs.

Stevie liked OC and used it for NeXT, while Microsoft leaned towards C++ and used that to implement their MFC library. The rest, as they say, is history.

Dylan is interesting, and I’m not saying Clojure doesn’t have some cool concepts.

But my primary point remains: Objective-C is not Clojure. If you want to program in that, or Dylan, or LISP, or whatever, then feel free.

But bolting on additional language features onto Objective-C? OC is already fairly complex and, as I said earlier, you’re implementing a bunch of program functionality in a non-standard way. That’s going to ramp up an already steep learning curve for new hires and for those who need to maintain your code.

Finally, and again to repeat, the sample given doesn’t fly. A tree of similar objects that require different behaviors? That’s a classic OO design pattern.

But showing an incomplete OO design, and then comparing that to “improved” code that serves to illustrate only one aspect of the system at hand is to setup that straw man I spoke of earlier.

Type-specific behaviors must exist SOMEWHERE, and in OO we combine them into tight back boxes. Dispatching multiple behavior methods throughout the code might seem easier, but comes at its own cost.

I’ll show mine if you show yours. (grin) I mean, at least the original SourceListItem example you provided was fully functional.

Where are your macro definitions? Where are your NSDictionary and NSMutableDictionary category additions? Where’s the code that walks the dictionary definitions, and actually creates the SourceListItems that PXSourceList expects to see?

How much code to I need to port from project to project to add this functionality. In a team effort, what’s the learning curve needed to bring everyone else up to speed?

Based on all of those things, the “Clojure” example fails to deliver.

As you yourself just pointed out, it’s easy to demonstrate the superiority of “code brevity” if you hide all of your implementation details.

at least the original SourceListItem example you provided was fully functional.

The source I gave was equivalent in functionality to the original quoted source (OK, maybe I forgot to include about 2 lines for the macros. Sorry.).

The point is that once you have the basic fundamentals done (the categories, which I’ve written for you), you don’t need to do anything except specify a protocol. I do not consider the fundamentals necessary to show, because they are coded only _once_. You have to create a new class for each type you want, which involves creating 2 new files per class. Each class has to have getters and setters written for it, internal instance variables, etc. Each class is unique to a high degree and makes it much more difficult to apply functions to it.

Using the alternative presented, all that’s necessary is the specification of a Protocol. That’s it.

As mentioned, no one is forcing you to use this. Do what feels right for you.

But bolting on additional language features onto Objective-C? OC is already fairly complex and, as I said earlier, you’re implementing a bunch of program functionality in a non-standard way. That’s going to ramp up an already steep learning curve for new hires and for those who need to maintain your code

What’s non-standard in one language or paradigm, is standard in another. Whether something is “standard” or not should not be the sole deciding factor in your decision to do something. That’s called herd mentality, and often it leads to really bad results.

All that’s being done here the introduction of a cleaner paradigm to writing code in Objective-C, one that’s simpler, more flexible, and easier to understand than the one it’s replacing. That’s a win-win, I think.

“You have to create a new class for each type you want, which involves creating 2 new files per class. Each class has to have getters and setters written for it, internal instance variables, etc.”

The base class needs those, correct. As to the rest, who knows? Perhaps I’m using the class names to simply set internal parameters in a single object. That’s an implementation detail. But as long as I fulfill the contract defined by the interface, To the user, it’s all good.

But you’re right, because for the moment, it doesn’t jibe. You’re using a bunch of macros to create nested arrays and dictionaries, which could just as easily have been instantiated by reading an equally simple PLIST or from an XML definition “protocol”.

It makes it simple to define structures, true, but throws out type-safety and object-specific behavior for something to be specified later on.

Tell you what. Do the next article, and show the “later on”. Show some of those “hundreds of functions” that will operate on the data.

Show how you’re going to enforce type-specific behavior, such as enforcing the rule that only libraries and groups can have children.