April 25, 2012
MarkBernstein.org
 
Follow me on Twitter

Objective C: a quandary

Objective C is a fine language, but I miss some idioms from C++. (Yes, I could be using Objective C++; let’s leave that aside for a moment.)

One common idiom in C++ uses object lifetime to control resource allocation. For exampe, we might write:

{
StGraphicState saved(cg);
...set up coordinates
...set up a funny clip region
...do scary things
return;
}

The constructor for StGraphicState does a CGContextSaveGState and the destructor restores it. That means:

The idiom neatly encapsulates a host of balanced actions where we need to set up, open, allocate, or lock something here and want to be sure to tear down, close, release, or unlock it when we’re done. It makes the programmer’s intention clear in one place, declaring that the lifetime of the balanced action is the current scope.

As far as I can tell, Objective C has no real equivalent. (We don’t throw a lot of exceptions in Objective C, but the first two issues are very real.)

With ARC, it seems you could almost do this.

{
StGraphicState *saved=
  [[StGraphicsState alloc] initWithContext: cg];
...set up coordinates
...set up a funny clip region
...do scary things
return;
}

But, as I read the fine print, this might not work. saved is guaranteed to be destroyed eventually, so we’ll eventually do the restore. According to the fine print, the compiler is free to destroy saved at any point after its last use. So, if you don’t refer to saved after declaring it, the compiler could save your state and then restore it right away.

You could work around this in various ways:

{
StGraphicState *saved= [[StGraphicsState alloc] initWithContext: cg];
...set up coordinates
...set up a funny clip region
...do scary things
[saved self];
return;
}

but then you have to remember to refer to saved at the end of the scope and worry about the cleverness of the optimizing compiler – and the whole point of the idiom is to avoid having to remember.

Is there an alternative idiom?

The underlying concept comes, as I recall, from InterLISP, and probably came to C++ via Common Lisp. I don’t remember seeing the idiom in Smalltalk-80, but that’s a long time ago for me.

Update: Much email and Twitterage to suggest block wrappers that take a block and do the setup and restore themselves, Chris Deveraux, for example, suggests

WithSavedState( ^(CGContextRef cg){
 CGDrawSomething(cg);}

where WithSavedState takes a block as its argument. It then does the setup, runs the block and then does the teardown. . I'm still not entirely happy, but it makes sense.