Posts filed under 'magic'

Death to the Singleton

Even those like myself who haven’t had the occasion to work through Design Patterns should no doubt be familiar with the Singleton Pattern. Though it’s one of the most used software patterns, especially in API’s like the JDK and Cocoa, it’s also attracted its fair share of flak for a myriad array of reasons, chief among them being that they’re simply a global variable with a nice name.

Now, it’s none of my business how you implement your classes, and I’m a member of the school of thought that global variables (especially in scripting languages) are often necessary. What really frosts me about singleton classes is their verbosity. Take, for example, this snippet of Nu code:

(if (((NSFileManager defaultManager) fileExistsAtPath: somePath))
    ((NSFileManager defaultManager) copyItemAtPath:otherPath toPath:somePath error:nil)
    (else
        ((NSFileManager defaultManager) createDirectoryAtPath: somePath)))`

This is, needless to say, ugly and repetitive. One could create a temporary variable to hold the NSFileManager, but that would not be a remedy for the verbosity associated with singleton classes like this - it’s merely a stopgap measure, and adds more code that you have to read. What I’d really like to do is this:

(if ((NSFileManager fileExistsAtPath: somePath))
    (NSFileManager copyItemAtPath:otherPath toPath:somePath error:nil)
    (else
        (NSFileManager createDirectoryAtPath: somePath)))

that is, have every instance method on the default NSFileManager become a class method. Were I totally brain-dead, I would declare an extension to NSFileManager and create a class method for every instance method that I wanted to represent. Luckily, I’m not - there is a better way, and it involves the oh-so-magical handleUnknownMessage: withContext: message that every Nu object has.

(Incidentally, this trick requires the most recent revision of Nu from the git repository. Previously the handleUnknownMessage: withContext: message only worked with instances of classes, not class objects themselves - but one line of Objective-C fixed that!)

By declaring handleUnknownMessage: withContext: as a class method on NSFileManager, we can tell the NSFileManager class to forward any messages it can to the shared instance of NSFileManager. Here’s the code that allows one to do that:

(class NSFileManager
    (+ (id) handleUnknownMessage:(id)cdr withContext:(id)ctx
        ((NSFileManager defaultManager) sendMessage: cdr withContext: ctx)))

Beautiful. Now every unknown message sent to NSFileManager will be forwarded to (NSFileManager sharedInstance); this can be implemented with any other singleton class that you please. It’s dynamic behaviors like this that make Nu such a pleasure to work with (and Java so painful - I once wrote an equivalent of Ruby’s method_missing in Java. It was not pretty).


Add comment January 17, 2008

Do You Believe in (Coding) Magic?

This article reflects merely my own thoughts and opinions. I doubt it applies to you personally, so don’t think I’m proposing a new law.

Last night, as my LAN-party-attending friends and I drove home from the pizza place, I was asked to explain the concept of Turing-completeness. I managed to give a somewhat coherent overview of the topic without simultaneously befuddling my listeners, and gave examples of Turing-complete and non-complete languages. Listing off my favorite programming languages, all of which fell in the former category, I was struck by a realization, and drifted off into thought until awoken by the derision of my peers. :)

I appreciated the furor on reddit regarding my How to Beat Rails and Blocks != Functional Programming posts; debates between programmers are often informative and always entertaining. The contests between languages, though they rarely (if ever) change anyone’s mind, are fertile ground for inflammatory quotes and flame wars. But the realization I came to in the car yesterday was this - since almost all programming languages are Turing-complete, what’s the difference? At a fundamental level, they’re all the same, right?

Then why do I like Python and Ruby so much more than C or Java? Why, indeed, doesn’t everyone just write bare machine code? Am I wasting my time wondering about abstracts instead of actually coding? I pondered these questions through many hours of video games, and eventually came to a conclusion.

The largest factor in whether I like a language is its attitude towards “magical” behavior. “Magical” behavior is difficult to define - my best effort is ‘the ability to redefine the most fundamental aspects of the language’ - but here’s an example, taken straight from the perlvar man page:

$[
The index of the first element in an array, and of the first character in a substring. Default is 0, but you could theoretically set it to 1 to make Perl behave more like awk (or Fortran) when subscripting and when evaluating the index() and substr() functions.

Perl, which I loathe with every fiber of my being, condones - nay, encourages - the deep, evil, horrible black magic to find the quickest way around a problem. Ruby, which I like more and more with every passing day, allows for happy, Good-Witch-of-the-North-esque magic with metaprogramming, different eval() scopes and near-total introspection. Python, which I’ve loved since the seventh grade, really discourages the use of magic - custom infix operators are the extent to which Pythonistas have dabbled therein. However, it always tries to permit the clearest, most concise non-magical solution to a problem. Scheme, which I respect, isn’t so much a language as a wellspring of magic through which you can do whatever you want. In the right hands, it’s brilliant, and in the wrong ones impotent. Rails and Pylons reflect the different attitudes towards magic - Pylons requires you to render the templates explicitly, while Rails just evaluates instance variables and goes with the flow.

In summary, my preferred language depends on attitude towards magic - my favorite languages either allow for positive, as-readable-as-possible magic (Ruby) or disallow it altogether (Python.) Which is better? It depends on your situation - and on the necessity of good documentation. (Documentation, and therefore long-term maintainability, cannot coexist with magic.) Overall, though, I enjoy a little code magic - do you?


13 comments February 25, 2007


About Me



I'm a college freshman, passionate about technology, programming (especially Cocoa and Python), and Apple.

By the way, 'important shock' is an anagram for 'Patrick Thomson'.

Meta

Links

Categories

Top Posts

Blog Stats