Search

A Motivation for ivar decorations

Mark Dalrymple

7 min read

Apr 22, 2012

A Motivation for ivar decorations

An idiom used by some Objective-C programmers is prefixing instance variable names with underscores. You do see this with explicitly declared instance variables:

@interface BNRSoapBubble : NSObject {
    float _viscosity;
    NSString *_detergentBrand;
}
@end

Or via properties when you synthesize them:

// soapbubble.h
@property (whatever) float viscosity;
@property (whatever) NSString *detergentBrand;
// soapbubble.m
@synthesize viscosity = _viscosity;
@synthesize detergentBrand = _detergentBrand;

These synthesizes tell the compiler that each property should be backed by an instance variable whose name is prefixed by an underscore. The compiler names the backing instance variable after the property if you don’t provide an alternative.

OK, so why do programmers do this? Seems like it’s just extra busywork. I see two main reasons: one one involves style, and one involves safety.

It’s Not Reserved!

But first – there’s a common misconception, unfortunately promulgated by some book authors and others that Should Know Better, that Apple reserves leading underscore instance variables. That is totally not true. Apple reserves leading underscores on method names, but not instance variables. You can google for “Naming Properties and Data Types site:apple.com” to see the recommendations.

Being stylish

Many style guides, whether just your favorite way of laying out code, or from a corporate mandate, have instance variables (or member variables) decorated somehow to distinguish them from arguments or local variables. I use underscored instance variables to make my setters prettier:

- (void) setPonyName: (NSString *) ponyName {
    [_ponyName autorelease];
    _ponyName = [ponyName copy];
}

This way I can use “ponyName” as the argument, which I find very readable. I also like being able to see at a glance when something is an instance variable or not. One thing which I’m not a fan of is cooking up some kind of abbreviation, which is what many programmers do:

- (void) setPonyName: (NSString *) pn {
    [ponyName autorelease];
    ponyName = [pn copy];
}

I find “pn” hard to mentally pronounce. And I don’t like nomenclature like “myPonyName”, it sounds juvenile, reminiscent of “Fisher-Price My First Programming Lesson.”

Some people use a trailing underscore (that’s Google’s style), and folks also prefix or suffix with “m” for “member”. It’s all fine. One nice thing about the leading underscore is that it automatically participates in Key-Value Coding.

Being Safe

Nowadays, with dot notation, having the backing ivar being spelled the same as the property that it backs can cause subtle and difficult to track down bugs, bugs which are impossible to make if you prefix your instance variables.

huh?

Recall that with dot notation this line of code:

self.ponyName = @"Mikey";

is exactly the same as

[self setPonyName: @"Mikey"];

These two lines of code are identical. self.ponyName causes a method to be called. Code is run. All sorts of stuff happens. With manual memory management, you would be doing retains and releases. Potentially mutable arguments are copied. Subclasses can override setPonyName: and affect the incoming parameter, or do additional, necessary work. It’s pretty open-ended what can happen.

Now this code:

ponyName = @"Mikey";

just copies the four bytes (eight bytes on 64-bit Mac. I’m going to call it four bytes from here on out) of the address of @"Mikey" into the four bytes of the ponyName instance variable. None of your code is called. None of the subclass code is called. The pointer just points to a new object. Nothing else happens.

What if you were really intending to do self.ponyName here to take advantage of the extra work the method does? Because you’re just assigning the naked instance variable, the extra code inside of setPonyName: will not be run. It’s entirely possible that messes up your program state. Perhaps, for legal or regulatory reasons, you need to register all pony name changes. You’re now breakin’ the law, breakin’ the law.

A little more concretely. Consider this implementation:

@property (copy) NSString *name;
...
@synthesize name;
...
- (void) setPonyInfoFromPropertyDict: (NSDictionary *) ponyProperties {
    NSString *name = [ponyProperties objectForKey: @"Name"];
    ponyName = name;
}

The backing instance variable is the same as the property, without an underscore. We have assigned the four bytes of the address of the name to the instance variable. We did not copy it the string. We’ve broken the contract. This is a bug.

How could this bug manifest?

NSMutableString *mutableName =
    [NSMutableString stringWithString: @"Mikey"];
NSDictionary *ponyProperties =
    [NSDictionary dictionaryWithObject: mutableName
                  forKey: @"Name"];
[pony setPonyInfoFromPropertyDict: ponyProperties];
[mutableName setString: @"Wookiee"];

And now, whenever we ask for the pony’s name, it’ll be “Wookiee” instead of “Mikey”. By having a the backing instance variable be underscore-prefixed, the offending line of code:

    ponyName = name;

Would be flagged as an error by the compiler.

Trust me: at 3 in the morning across the country right before a trade show, hyped up on Dr Pepper and Slim Jims, it can be very hard to not read “self.blah” for “blah” if that’s what you’re expecting/hoping the code would do.

From The Real World

OK, we’re not all lucky enough to be developing a pony management system. How about a more concrete example that actually happened in real life? Some friends in the local CocoaHeads asked me to help debug a weird problem with their iPhone app. They’d tap a button on a screen which drew an image (amongst other stuff). Then they’d go back to their program’s main menu screen and come back to this page, and be greeted by a crash inside of UIImage.

The image page had a view with an UIImage property (which was pre-ARC):

@property (nonatomic, retain) UIImage *mapImage;

They got the map image from UIImage, and set the property:

mapImage = [UIImage imageNamed: @"Map"];

And then they’d do stuff with the image, like draw it in drawRect:

- (void) drawRect: (CGRect) rect {
    ...
    [mapImage drawInRect: someOtherRect];
    ...
} // drawRect

It drew fine, and but when they moved to a different part of the app and came back, it would crash.

Did you find the bug? I didn’t find it the first time I looked at the code. Go back and take a look.

I ended up doing an impromptu demo of Instruments retain count tracking to isolate it. Only when I noticed “That’s odd. It’s not being retained here” did I find it. It’s this:

mapImage = [UIImage imageNamed: @"Map"];

This says “Hey UIImage, get me an image called Map”. UIImage says “ok, here is the address of an image from my cache. Enjoy.”. The four bytes of that image address are copied to the four bytes of mapImage.

Notice the image is not retained. It was not manually retained here. It did not go through the setter method that would have retained it. That’s the bug.

What then happened is the user went to the other screen. It triggered a memory warning. UIImage reacted to the memory warning by to releasing all of its images. Because the map view didn’t retain the image, that particular image’s retain count went to zero, and the image was destroyed. My friend still had a pointer to it, which is now a dangling reference, and it crashed the next time it tried to draw the image.

They really wanted to do

self.mapImage = [UIImage imageNamed: @"Map"];

which causes setMapImage: to be called, which would have retained the object.

How would the underscore prefix fix this? With underscore prefixed instance variables, these lines of code compile and work:

UIImage *map = [UIImage imageNamed: @"Map"];
self.mapImage = map;
_mapImage = map;

and it’s obvious what’s a self-send, and what’s an ivar assignment. “Oh. Underscore. ivar assignment.”

You would get a compiler error, not just a warning but a stop-you-in-your-tracks error, with the morally ambiguous code:

mapImage = map;

The error happens because the compiler doesn’t know what mapImage is. It’s not an instance variable (that’s _mapImage). It’s not a property access (that’s self.mapImage), therefore it’s an error.

What About ARC?

So what about ARC? Instance variable pointers are strong references, so the original case of using instance variables named after the property would have retained the map:

mapImage = map;

It would therefore not be accidentally destroyed, and the program wouldn’t crash. Problem Solved! No need for those pesky underscores and the their corresponding confusion and religious debates.

What if the original intent of that code was to vector through the setter method? The semantics of the assignment is now incorrect. Harkening back to the Pony Regulatory Agency, it’s possible to have code that works (or at least doesn’t crash and the screen seems to display the correct stuff) but is still incorrect because necessary support work isn’t being done. ARC has now masked this problem, turning an obvious crasher with manual memory management into a silent bug.

self.done = YES;

Readability reasons aside (which are purely stylistic), the safety afforded by the different instance variable and property names when using dot notation for setters is why I prefix my ivars with underscores. Everything in Advanced Mac OS X Programming: The Big Nerd Ranch Guide adopts this pattern as well (there’s a brief discussion at the bottom of page 38 of the dead-trees version). It’s a pretty easy way to prevent this particular class of bugs. In the course of teaching various courses, and talking with folks at conferences, many programmers are still fuzzy over the differences between property-method-calling and just assigning a pointer. Adopting this underscore-prefix technique is a rote way of avoiding a class of problems until the concepts have had time to sink in.

Mark Dalrymple

Author Big Nerd Ranch

MarkD is a long-time Unix and Mac developer, having worked at AOL, Google, and several start-ups over the years.  He’s the author of Advanced Mac OS X Programming: The Big Nerd Ranch Guide, over 100 blog posts for Big Nerd Ranch, and an occasional speaker at conferences. Believing in the power of community, he’s a co-founder of CocoaHeads, an international Mac and iPhone meetup, and runs the Pittsburgh PA chapter. In his spare time, he plays orchestral and swing band music.

Speak with a Nerd

Schedule a call today! Our team of Nerds are ready to help

Let's Talk

Related Posts

We are ready to discuss your needs.

Not applicable? Click here to schedule a call.

Stay in Touch WITH Big Nerd Ranch News