Don’t Coddle Your Code

Jeff LaMarche presents a rundown on whether Objective-C dealloc implementations should bother nil’ing out an instance variable after releasing it.

LaMarche offers a fairly balanced presentation of the two sides, but in my opinion he gives too much credibility to the argument that nil’ing is a good idea. He essentially embraces the argument that nil’ing the variables in production code is wise, because it might mask crashing bugs that would obviously vex the user:

Generally speaking, this is only going to happen if you’ve got a bug elsewhere in your code, but let’s face it, you may very well. Anyone who codes on the assumption that all of their code is perfect is begging for a smackdown.

And speaking specifically about the approach I prefer, leaving the instance variable alone and not bothering to nil it out:

On the other hand, that approach is really, really bad in a shipping application because you really don’t want to crash on your users if you can avoid it.

I disagree with the assertion that avoiding crashes at all costs in shipping code is the right priority. The biggest disservice you can do to your users is to allow them to run code that has unpredictable behavior. The whole point of programming is to make computers accomplish tasks in predictable ways. Sure, we all make mistakes as programmers, but giving in to the chaos and putting up safety nets “just in case” is not the right approach, especially considering it has unwanted consequences.

Consider that by masking the crash from occurring in the wild, you may be putting off detection of and resolution of the underlying bug indefinitely. But if your application has a crash reporter, or if you take advantage of Apple’s iOS crash reports, you will learn quickly that there are issues needing to be resolved.

It is reasonable to take steps that mask mysterious crashes, but this should only be done after you know there are actually crashes to prevent. Masking the symptoms in a blanket manner is akin to cutting half the phone lines in the neighborhood and celebrating the reduced number of 911 calls.

It’s also worth noting that LaMarche’s defense of nil’ing out instance variables hinges on the presumption that messaging nil is safe. True, messaging nil will not cause a crash. But is that safe? Not if it changes the behavior of your code in unpredictable ways. Consider this incredibly contrived Cocoa-based nuclear arms controller:

if ([mDiplomat didReturnGestureOfPeace] == NO)
{
[[NuclearWarehouse nuclearMissile] launch];
}

By LaMarche’s reasoning, it’s a good idea to nil out the mDiplomat variable on release, so that it won’t crash when you message it. But in this case, messaging nil for a BOOL result causes a logical flaw in the program, with obviously dire consequences. If the instance variable were not set to nil, it would probably crash before the launch message could ever be sent.

We should aim to comprehend what our software actually does. Deliberately decreasing the symptoms of problematic code won’t lead us any closer to that understanding. Ship the best code you have to your customers, and if it crashes, try to fix the root cause of the crash as quickly as possible. Don’t get in the habit of writing “hope this fixes it” code, and by all means don’t adopt that philosophy as a boilerplate coding habit.