As You Were

Devin Coughlin's blog.
Styles: Serious Spare

April 28, 2007

Syncrospector.app is a major memory hog

I'd noticed a marked decline in my laptop's performance in the last month or so. There was much thrashing and disappearing hard disk space. Since my PowerBook is maxed out on RAM, I was more or less resigned to the notion that it was time to get a new computer. But today, in lieu of swearing vociferously and getting a snack while waiting for the swap storm to settle down, I decided to, you know, investigate. It turns out Syncrospector (an unsupported but invaluable utility Apple provides for debugging your app's interaction with SyncServices) chews through memory like a horde of Rodentia on weed. Every time I ran my sync unit tests while Syncrospector was running, it would run through 2+Gbs of virtual memory, and push out everything else out in the process. It's a simple fix (don't run Syncrospector and unit tests simultaneously) but, unfortunately, it means I don't yet have an excuse to buy that shiny new 8-core Mac Pro.
Posted by coughlin at 12:56 PM

April 27, 2007

ObjC-style method calling in Ruby

I don't speak Japanese, but this looks promising (even if they do commit the deviant spacing heresy).

If it's true, some day we'll be writing our Cocoa programs in Ruby for real.

(Via Irz's Diary)

Posted by coughlin at 10:05 AM

April 25, 2007

Call Down, Notify Up

In response to a post by Brent Simmons on large Cocoa projects (with follow-ups by Blake Seely, Daniel Jalkut, and Michael Tsai), Rentzsch lays out a theory of application design that I wholeheartedly endorse:

"Think of your Cocoa application as a layer cake: Foundation at the bottom, AppKit in the middle, your code on top. It’s OK for higher levels to know about and use lower levels, but not going the other way. By keeping the lower levels ignorant of its clients (the higher levels), you keep them reusable."

Which brings me to my one and only coding mantra:

Call Down, Notify Up.

In Cocoa this means that while you can directly call methods on objects defined in layers below you, those objects should never call methods specific to you — if they need to communicate with the upper layer, they should do so via return argument, explicitly defined delegate method, or NSNotification. I used to keep this written on a post-it note stuck to my monitor. That damn stickie is the closest I've ever gotten to a universal design oracle.

Call Down, Notify Up is easier in Objective-C than in any other language I've ever used, which is one of the reasons why I'm willing to put up with its crap.

(Aside 1: Call Up, Notify Down is the mirror technique to avoid excessive coupling. You don't see this pattern used explicitly very often in object-oriented desktop apps, but manual event dispatching made this more common in the Mac Toolbox days. You also sometimes saw it in embedded OS kernels that were all bottom half and no top.)

It's also nice to see that other people keep all their source files in a single huge directory and only organize them within Xcode. This seems to be a fairly good indicator of Mac vs. Unix heritage. The Mac folks have relied on GUI IDE's since time immemorial, while on the Unix side everything had to work from the command-line.

(Aside 2: Thinking about this made me fire up THINK Pascal [it still runs, thank you Classic!] and I remembered why, much to the chagrin of those collaborated with, Geneva 9 was for many years my programming font of choice. Pascal in Geneva 9 is stunningly beautiful, a true joy to look at. Nothing in the monospaced world even comes close.)

Posted by coughlin at 11:58 PM

April 15, 2007

Top 100 books of the last 25 years

So the Daily Telegraph has published a list of the top 100 books of the last 25 years, as determined by asking the staff of Waterstone's (a British bookstore) for their five favorite books of the period.

I was suprised to see so many books on the list that had been turned into movies. I wonder if it is because good books are made into movies, or because having a movie made of a book makes people remember it better when surveyed. The latter would account for the presence of The Da Vinci code and Nick Horny on the list. . .

The list also bolsters my conviction that Margaret Atwood is the best writer of the last 25 years, with Ian McEwan and Haruki Murakami duking it out for a distant second.

Posted by coughlin at 11:04 PM

April 14, 2007

-[NSDictionary dictionaryWithObjectsAndKeys:] considered harmful

Yeah, the title is over-used, but -[NSDictionary dictionaryWithObjectsAndKeys:] will seriously bite you in the ass if you aren't careful.

NSDictionary is Apple's implementation of a hashtable (or associative array) in Objective-C. It's pretty standard stuff; you can store and retrieve objects keyed on arbitrary (often string) values, lookup is of constantish time complexity, etc. The only real gotcha is that the key value has to support immutable copying (i.e. -copyWithZone:) because NSDictionary doesn't want the key changing underneath it.

One particularly common use for NSDictionary is as a container tying together a bunch of disparate objects. This way you only have to cart around a single object reference.

A common way to create a dictionary in Cocoa is this:

NSURL *url = @"http://www.google.com";
NSImage *favicon = Some Image
NSString *title = @"Google";

NSDictionary *bookmark = [NSDictionary dictionaryWithObjectsAndKeys:url, @"URL", favicon, @"FAVICON", title, @"TITLE", nil];

Here the method -[NSDictionary dictionaryWithObjectsAndKeys:] takes your standard C-style variable argument list. Since varargs in C are brain dead and don't know how may arguments they have (*) you pass nil as the last argument to delimit the end of the list. This isn't ambiguous because you can't put nil in an NSDictionary. You end up with a dictionary that looks like this:

bookmark = { URL => http://www.google.com/,
  FAVICON => Some Image,
  TITLE => "Google" 
}

While this incantation is concise and very convenient, it is going to kick your ass someday — and you might not even know it.

What happens if favicon is nil?

If favicon is nil, then you're essentially creating the bookmark dictionary as follows:

NSDictionary *bookmark = [NSDictionary dictionaryWithObjectsAndKeys:url, @"URL", nil, @"FAVICON", title, @"TITLE", nil];
Since that first nil is interpreted as the end of arguments, the dictionary looks like:
bookmark = { URL => http://www.google.com/
}
The "title" key-value pair is missing. That's right — silent data loss. Oops.

A safer, but much more clunky way to construct a dictionary is:

NSURL *url = ...
NSImage *favicon = ...
NSString *title = ...

NSMutableDictionary *bookmark = [NSMutableDictionary dictionary];

if (url != nil)
    [bookmark setObject:url forKey:@"URL"];
    
if (favicon != nil)
    [bookmark setObject:favicon forKey:@"FAVICON"];
    
if (title != nil)
    [bookmark setObject:title forKey:@"TITLE"];
Ick, right? Not just more lines of code, but more codepaths. But no silent data loss. And if you expect your objects to be non-nil, you can leave out the conditionals because -[NSDictionary setObject:forKey:] will throw an exception if the object is nil.(**)

After recently tracking down several bugs to just this kind of problem, I've promised myself I'm never going to use -[NSDictionary dictionaryWithObjectsAndKeys:] again.

There is a similarly pernicious problem with -[NSArray arrayWithObjects:] and all other containers that use nil-terminated varargs, but, for whatever reason, I've found that the dictionary case is the one that always gets me.

(*) The stupidity with which C handles varargs leads to all sorts of nasty bugs, including format string attacks.

(**) The fact that you can't set an object to be nil in an NSMutableDictionary has the odd consequence that

[dictionary setObject:[dictionary objectForKey:@"FOO"] forKey:@"FOO"]
doesn't always work.

Posted by coughlin at 11:49 PM

Back on the bandwagon again

So, mostly to keep an eye on C4, but also because I am interested in the idea of a "full-time intimate community" (or I would be, if I had any friends), I now have a twitter account. I'm using twitterific and so far it works great.

Posted by coughlin at 12:37 PM

A Vacation From Vacation

I see David LeBer (whom I meet last year at C4[0]) is disappointed that C4[1] is taking place during his summer vacation.

I'm in a similar situation. It is a testament to the total awesomeness of C4 that I am considering taking a vacation from vacation in order to attend this year.

Posted by coughlin at 12:25 PM