Mistakes Were Made: Initialize Your Locals

“Mistakes Were Made” may or may not end up being a post series where we talk about actual things we have done wrong, and the lessons thereby learned.  The uncertainty is about whether revealing all this stuff will make us look unemployable.  We’re not, I promise.

One of the pleasant little details that make working in Objective-C such a joy is that instance variables are automatically zeroed out at creation.  That means that when you define a pointer in your object’s interface, you don’t have to explicitly set it to NULL in the init method — the compiler will take care of that for you, freeing your mental capacity for bigger and better things.  Languages with more strictly managed memory, like Java, will also do this, but looser languages like C and C++ will not.

Great, so what?

Problem is, you might get used to this and expect local variables to come zeroed out too.  They don’t.  I knew this, but was reminded of it the hard way recently.  A certain nameless application on the App Store has a table view that contains another table view in one cell.  The height for this outer cell is calculated thusly:

- (float)preferredHeight
{
	float height;
	int i;
	for (i = 0; i < numCells; i++)
    {
		height += cellHeights[i];
    }
    return height;
}

Whoops.  Anyone see the problem?  That’s right, height is used uninitialized — any old junk values that happened to be in there are added to the final count.  This is a particularly pernicious problem because on debug builds, the memory happened to be set up such that the initial value for height was somewhere around 9.71498046e-30 — for all practical purposes, zero.  Even on a release build tested locally, it was 14, easy enough not to notice.  It wasn’t until the app made it out into the wide world that I started to see real issues, but now, many people using that nameless application are seeing a cell that’s way taller than it should be.

What do I do?

There’s a warning for that!  Add -Wuninitialized to your build flags, or if you’re using Xcode, turn on the warning for “Uninitialized Automatic Variables” under Build Settings.  For some reason this is NOT the default for new Xcode projects!  I guess Apple expects us all to be smarter than I am.  There’s also -Wmaybe-uninitialized, which is more aggressive about warning when the variable may or may not have a value set, like cases in a switch statement that you know are impossible but the compiler doesn’t.  (Switch statements should always have a default!)

Of course, you should always initialize your variables anyway.  The warning should serve as a safety net, but clearly you can’t depend on it.  Given this, it might make sense to zero out your instance variables in your init methods, for consistency’s sake: it’s easier to do the wrong thing if sometimes it’s the right thing.  I know I would rather do too much zeroing than too little.

Joel Kraut

About Joel Kraut

Developing on Apple platforms for, holy shit, over ten years now. Find me on linkedin and twitter. My personal website is foon.us.
This entry was posted in Code and tagged , , . Bookmark the permalink.