Posts filed under 'programming'

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

How Tim Burks and Nu Stole the Show at C4[1]

Edit: Fixed some factual inaccuracies about the language itself.

Tim Burks, noted contributor to RubyCocoa and creator of RubyObjC, gave a talk at C4[1] about his experiences with creating a Ruby <-> ObjectiveC bridge, and the problems he overcame in doing so. It was an interesting presentation, and we were all suitably appreciative when he showed his custom visual chip-design software written in Ruby with a Cocoa interface.

And then he dropped a bombshell.

For the past year, Tim’s been working on a new dialect of Lisp - written in Objective-C - called Nu. Here are its features (more precisely, here are the ones that I remember; I was so awestruck that many went over my head):

  • Interpreted, running on top of Objective-C.
  • Scheme-y syntax. Everything is an s-expression (data is code, code is data). Variable assignment was done without let-clauses (which are a pain in the ass) - all one has to do was (set varname value).
  • Variable sigils to indicate variable scope.
  • True object-orientation - everything is an object.
  • True closures with the do-statement - which, incidentally, is how Ruby should have done it.
  • Macros. HOLY CRAP, MACROS! When Tim showed us an example of using define-macro for syntactical abstraction, Wolf Rentzsch and I started spontaneously applauding. His example even contained an example of absolutely beautiful exception handling that should be familiar to anyone with any ObjC or Ruby experience.
  • Symbol generation (__) to make macros hygenic and prevent variable name conflicts.
  • Nu data objects are Cocoa classes - the strings are NSStrings, the arrays NSArrays, etc.
  • Ability to create new Obj-C classes from inside Nu.
  • Interfaces with Cocoa libraries - you can access Core Data stores from within Nu in a much easier fashion than pure ObjC, thanks to Tim’s very clever idea of using a $session global to store the NSManagedObjectModel, NSManagedObjectContext, and NSPersistentStoreCoordinator.
  • Ruby-style string interpolation with #{}.
  • Regular expressions.
  • Positively drool-inducing metaprogramming, including a simulation of Ruby’s method_missing functionality.
  • A web-based templating system similar to ERb in 80 lines of Nu code - compare that with the 422 lines of code in erb.rb.

Tim showed us a MarsEdit-like blog editor written entirely in Nu, using Core Data as its backend - and then showed us the built-in Nu web server inside that program, complete with beautiful CSS/HTML/Ajax.

As F-Script is to Smalltalk, so Nu is to Lisp. Tim said that he hopes someday to open-source Nu; if he does, he will introduce what is quite possibly the most exciting development in the Lisp-related community in a long time. I don’t think I speak for just myself when I say I cannot wait to get my hands on it.


3 comments August 12, 2007

Map, Filter and Reduce in Cocoa

After working in Scheme, Python or Ruby, all of which (more or less) support function objects and the map(), filter() and reduce() functions, languages that don’t seem to be somewhat cumbersome. Cocoa manages to get these paradigms almost correctly implemented.

map()

One would think that Objective-C’s ability to pass functions around as objects in the form of selectors would make writing a map() method easy. Observe, however, the crucial differences of the NSArray equivalent to map(). (For those unfamilar with it, map(), when given an array and a method/function taking one argument, returns the result of mapping the function onto each item of the array.)

From the NSArray documentation:

makeObjectsPerformSelector:

Sends the aSelector message to each object in the array, starting with the first object and continuing through the array to the last object.

- (void)makeObjectsPerformSelector:(SEL)aSelector
Discussion

The aSelector method must not take any arguments. It shouldn’t have the side effect of modifying the receiving array.

This is different on no fewer than two levels. Firstly, even in the NSMutableArray subclass, this method is not allowed to have side effects. Frankly, I can think of few situations in which I would need to map an idempotent function onto an array; the point of map() is to be able to apply a function quickly to every element of an array and get back the changes! Secondly, an unaware or hurried programmer would think that this function was implemented so that one could write code like this:

- (void)printAnObject:(id)obj
{
NSLog([obj description]);
}

and then do this:
[anArray makeObjectsPerformSelector: @selector(printAnObject:)];

This is not the case - the above code would just make each element call printAnObject:, not call printAnObject with each element. I’m sure that to some it seems obvious, but I, for one, found this to be an insidiously tricky wart.

However, there is a (limited) workaround.

NSArray’s valueForKey: method (somewhat counter-intuitively) returns the result of invoking valueForKey on each of the array’s elements. As such, one can map KVC functions onto arrays. For example:

NSArray *arr = [NSArray arrayWithObjects: @"Get", @"CenterStage", @"0.6.2", @"because", @"it", @"rocks", nil];
[arr objectForKey: @"length"]; // returns [3, 10, 6, 7, 2, 5]

This can be used in many helpful ways; sadly, it only works on KVC-compliant properties/methods.

Anyway, moving on…

filter()

With OS X 10.4, Apple introduced the NSArray filteredArrayUsingPredicate: method, which allows one to filter an array based on criteria established by an NSPredicate. Observe:

NSArray *arr = [NSArray arrayWithObjects: @"This", @"is", @"the", @"first", @"CenterStage", @"release", @"I", @"helped", nil];
arr = [arr filteredArrayWithPredicate: [NSPredicate predicateWithFormat: @"SELF.length > 5"]]; // arr is now [@"CenterStage", "@"release", @"helped"]

Verbose, but useful.

reduce()

Frankly, Apple don’t give us any way to do this in pure Cocoa. The best way I’ve found (if you really need this, which is less often than one needs map() and filter()) is to use the F-Script framework and apply the \ operator to an array. Unfortunately, this takes a bit of overhead.

In conclusion, Cocoa and Objective-C almost bring us the joys of functional programming. We can only hope that Leopard and Obj-C 2.0 improve on these in some way.

List comprehensions, anyone?


3 comments June 18, 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