The Importance of Failing Fast

Writing software is hard. If the guy next to you hasn’t created ten new bugs, management hasn’t added 10 new features, the customer hasn’t tightened the due date by a week, and your technical lead hasn’t passed a new programming commandment (“Thou shalt not use identifiers with fewer than 4 characters!”) – all by noon – then it’s a good day in Developerstan.

Writing software is hard enough just dealing with the practical, every-day, mundane bits without even having to think about the difficulty added by the actual technical work itself. To write really good, clean, correct code, the programmer has to have a million tiny things in his head – “What does Integer.parseInt() throw if it fails?” “Which directory is ServletContext.getResourceAsStream() relative to?” “Which language is this product in again?” – before he can even write a single line of code. And the really good programmer has to check all his assumptions and return codes before he can even get down to business.

Wouldn’t it be nice if your tools yelled at you when you miss something?

This is why things like exceptions are so good for productivity. Whereas C functions only tell you they failed by returning a value, which you probably ignore a lot anyway (when was the last time you checked the return code for printf()?), languages like Java and Python and C++ explode in a massive fireball of fail when something goes wrong. This means the really good programmer doesn’t have to check every. single. return. code. Instead, he can just say “if anything in here fails, just do this.” Much easier.

So, anything that makes detecting and managing failure faster and easier is A Good Thing. And, as a corollary, anything that makes detecting and managing failure harder is A Bad Thing. But come on, man, this is 2010. Surely the modern languages we use to power the products around us are marvels of engineering and convenience for programmers? Right? And certainly nothing’s running around hiding errors from programmers.

If only.

The Importance of Failing Fast

Because finding errors is hard enough on programmers as it is, a good toolset fails fast. That is, the best tools kick and scream and yell at the programmer when he’s made a mistake, preferably as close to the actual programming error as possible so that the error is easy to track down.

A huge factor in how fast the code of a program fails is the programming language it uses. Language features like assert, exceptions, baked-in synchronization, and so on make failing fast easy and automatic, so it happens more.

Here’s a spectrum of how fast a few popular languages fail:

NOTE:Some great issues about complexity and disabling exceptions in C++ were brought up in the comments, and how these “features” mean that C++ probably (at best) ties with C. these are great points, and i agree.

On the two ends of the spectrum we have Java and Assembler.

Java yells and screams at the drop of a hat. Java programmers are so used to seeing things like NullPointerExceptions, FileNotFoundExceptions, and SocketTimeOutexceptions that people have made up drinking games around them. Java fails so fast that a lot of programs fail before they even run because of Java’s bondage type system. (There’s probably a joke in there somewhere.) Java programmers can generally feel pretty confident that their language will tell them when something anything has gone wrong.

Assembler, on the other hand, fails very slowly. Assembler has no type system to speak of, no logging, no exceptions, and generally nothing to help a programmer find bugs. When a user hits a bug in an assembly program, there’s nothing in the language itself that helps a programmer understand it and track it down. He’s totally on his own.

C and his kooky younger brother C++ are kind of in the middle. With C, you have to check status codes, and you can easily have runaway memory bugs that are extremely difficult to track down, but C at least has the decency to crash when things go south.

Dynamic languages like Ruby and Python end up being kind of a mixed bag. Scripting languages are fail-fast at runtime, but have no safeguards at all before then – frequently not even a simple parsing test – so bugs can pop up seemingly out of nowhere. Ultimately, dynamic languages rely on their flexibility for robustness, which kind of works but kind of doesn’t.

Dammit, Jones, What the Hell Are Knoll Pointers?!

If you’re paying really close attention, you’ve noticed that we haven’t talked about Objective C yet. Don’t worry, I haven’t forgotten. I’ve just been coming up with new four-letter words to use.

The worst kind of failure by far is the kind that doesn’t look like a failure. The languages we’ve talked about so far have had varying ways of reporting errors, with some being faster than others, but at least all of them reported errors when they happened. All languages do that, right?

It turns out: No.

Consider the following snippet of Java:

Bar bar=this.getFoo().getBar();

In Java, what happens if getFoo() returns null? The program throws a NullPointerException with a stack trace, telling you exactly where the null pointer was encountered. This is The Right Thing. Java gets a gold star.

Now, what happens if we do the same thing in Objective C:

Bar *bar=[[self foo] bar];

In Objective C, if foo returns nil (Objective-C’s version of null), then surely the program throws an exception, right? Wrong. If foo returns nil, the variable bar contains nil after the statement executes. That’s right, ladies and gentlemen: Objective C’s null value can be dereferenced, and happily returns itself when that happens.

Awesome.

This was obviously an explicit design choice. You just know some manager somewhere said to an employee “Gosh, Jones, programs sure do crash a lot. It’s because of “knoll” pointers? What the hell are those? Dammit, Jones, make sure our programs don’t have any knoll pointers!” So Jones decided that he’d make dereferencing null pointers fail silently instead of crash, call null niljust in case, and declare victory. (I’m sure Jones got a pat on the back and a promotion to management.)

So, purely hypothetically – it’s not like this actually happened to me when I was working on an iPhone app or anything – let’s say you’ve got a method that takes one object, does a bunch of stuff to it, and then returns another object. It works like a charm. Then you add another call somewhere else in the program, and BAM, this call returns nil. No problem, we’ll just check the stack trace from our exception… Oh wait, dereferencing nil fails silently. Well, the bug must have been in the last assignment, because otherwise our program would have crashed… Oh wait, dereferencing nil fails silently. Well, we’ll just check the method, there can’t be that many ways we could have gotten nil… Oh wait, since nil propagates, it could from any one of 50 of these calls.

So, What Have We Learned?

Programming is hard. Programmers have enough work to do without having to chase failures when the failures aren’t hiding from them. Failing silently is a great example of a hiding failure. So, failing silently is bad. Really bad. Take a minute to stop and think about how bad failing silently is. Mayo on a burger you ordered dry? Nope, much worse than that. Box of kittens hit by a school bus? Now we’re getting there. Palin elected president in 2012? Whoa. Not quite that bad.

But close.

EDIT: Some interesting issues about nil and the null object pattern were brought up on reddit and here in the comments. Personally, I don’t buy this pattern as A Good Thing, and the ultimately small gain you get from applying this pattern doesn’t justify the cost. I explain in more depth here and here.

EDIT: It has also been pointed out that I’m a little snarky in this post. Heh. Yes, i definitely am. But the post is tagged rant for a reason, for what that’s worth. :)

EDIT: A comment below tells me that yes, this feature is annoying at first, but the annoyance is likely to pass, and be replaced by better, more concise code. I sure hope so. Perhaps I’m being heavy-handed here, but in my mind this feature is still very tricky, especially for new Objective-C developers.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

c vs. c++

I’m not sure if C++ is a clear winner over C in this case. True, both languages fall victim to the same class of insidious memory bugs that can cause corruption which crashes the program far away from the actual bug.

Also true that C++ has exceptions but not necessarily for everything. C++ may throw exceptions (if you have them enabled, if they’re used by a particular class, etc.) but C++ is a much more subtle and dangerous language (see the C++ FQA) than C.

At best, I would give them a tie. And I’m not sure if I’d rank the scripting languages so high either for the exact reason you state. There are real advantages to having compile time checks and static typing.

one more thing....

Forgot to say that I absolutely agree with your overall argument. I want crashes, early, hard and often when I’m developing code. That’s why the objective-C nil dereferencing makes me go yikes. I don’t know what I’d do if null didn’t cause a crash. I rely on that.

You know, you could just go

You know, you could just go read up on why Objective-C lets you send messages to null pointers (and not dereference them), instead of making up snarky little stories about how stupid people are. There are actually good reasons for that behaviour. It is also incredibly dishonest to claim that you could have a nil propagate from “any one of 50 of these calls”. That is not how code works in practice. In practice, you chain a few calls at most, and it’s usually blindingly obvious which one is the one that can return a null pointer at all.

And then you’re completely ignoring that Objective-C extensively uses exceptions to signal all kinds of errors much like Java.

You kind of flubbed an otherwise good article with that last part.

thanks, but i disagree

You know, you could just go read up on why Objective-C lets you send messages to null pointers (and not dereference them)

i’m going to cross-post a little bit of a comment i made at reddit because it’s relevant here, forgive the redundancy:

yes, i’m familiar with the “message passing” semantics Objective C uses, as borrowed from Smalltalk (and other) languages. and yes, i understand that it’s different from dereferencing. (so, [nil foo] is different from *nil, especially where the former does not crash while the latter does.)

i didn’t mention this in the post because, honestly, i didn’t expect it to come up, and i think it muddies the waters. good catch.

that having been said, i don’t personally buy the “Null Object” pattern. (@Peaker, thanks for giving it a name, i hadn’t heard it called that before.)

yes, this pattern makes some things really easy. the best example is turning functionality on and off with a simple assignment. for example, if you want to turn logging on in a class, you can imagine doing something like self.logger = [FileLogger loggerWithFile:@"error.log"], whereas if you want to turn logging off, you would just do self.logger = nil. in the code, you just call [self.logger logMessage:@"Hello" atLevel:Verbose], and it Just Works, regardless of whether the value is nil or has an actual object.

however, in my opinion, this is a huge price to pay for what is basically a non-feature. while Null Object makes this really easy, it’s still easy without this pattern. for example, in Java, you’d just make a NullLogger class that does nothing but ignore all log messages instead of log them (so, has empty method bodies), and assign that instead of nil. if you’re worried about a bunch of instances of NullLogger floating around, then just make one global instance called NullLogger.LOGGER and be done. there’s no state, so you don’t have to worry about synchronization.

so yeah, Null Object makes some things really easy, but to me the argument isn’t very strong because these things are still really easy without it and you give up a lot of error-catching abilities to have it. to me, the costs and benefits just don’t line up.

so yeah, i understand the message passing argument, and it’s a good one. you’re right, i didn’t mention it, and in retrospect, i probably should have. thanks for bringing it up! but personally i just don’t buy it.

instead of making up snarky little stories about how stupid people are.

heh yeah, you’re right, i’m definitely a little snarky here. maybe it’s not fair. but the post is tagged as a rant, for what that’s worth. :)

It is also incredibly dishonest to claim that you could have a nil propagate from “any one of 50 of these calls”. That is not how code works in practice. In practice, you chain a few calls at most, and it’s usually blindingly obvious which one is the one that can return a null pointer at all.

i have to disagree here. my problem isn’t that nil propagates through chained method calls, which you’re right, it does, but that it propagates through assignments. if all i’m worried about is where in the chain of method calls a nil came from, then that’s pretty easy to track down. the problem is when i don’t have confidence that a nil came as the result of a a call in a chain instead of being propagated from some code that came earlier. that’s when the “any of these 50 calls” thing comes into play, and it definitely has bitten me. maybe i just don’t “get” this part of Obj-C yet, but that doesn’t mean i can’t find it extremely irritating.

And then you’re completely ignoring that Objective-C extensively uses exceptions to signal all kinds of errors much like Java.

i’m going to cross-post a little more reddit comment here. again, sorry for the copy pasta. the context here is a discussion of how Obj-C does throw exceptions much like Java (apropos!):

a really good example here is a call that does more than one thing. consider NSKeyedArchiver archiveRootObject: toFile: specifically. that particular method just returns a BOOL to indicate success. however, if you think about the underlying implementation, it can fail in at least 2 important ways: either it can’t encode the root object, or it can’t write the the file. in Java, you’d get a different exception for either case, which would help you tease apart the problem. in Objective-C, though, you just get a TRUE/FALSE that doesn’t tell you anything about why it fails, just that it failed.

that’s an important distinction, especially for a new Objective-C programmer just starting out.

Obj-C does throw exceptions, but it’s philosophy about throwing the is different. i think this is a cultural issue, as opposed to a language issue, but it still matters.

thanks for your comment. i hope the discussion continues, it’s interesting.

really great points

Also true that C++ has exceptions but not necessarily for everything. C++ may throw exceptions (if you have them enabled, if they’re used by a particular class, etc.)

really great point there, totally agree. don’t think i knew hat you can actually turn off exceptions in C++. whoa.

but C++ is a much more subtle and dangerous language (see the C++ FQA) than C.

heh yes, that’s a great way to say it. subtle and dangerous it is. C++ is a temperamental lady, and hell hath no fury…

At best, I would give them a tie.

you’re making good sense here, too. i agree.

And I’m not sure if I’d rank the scripting languages so high either for the exact reason you state. There are real advantages to having compile time checks and static typing.

sing it, buddy. personally, i’m uncomfortable without static checks. it gives me confidence that i’m not doing something completely boneheaded. but maybe i just haven’t learned to love dynamic types yet? is there anyone out there who likes dynamic languages who can give some perspective here?

Forgot to say that I absolutely agree with your overall argument. I want crashes, early, hard and often when I’m developing code. That’s why the objective-C nil dereferencing makes me go yikes. I don’t know what I’d do if null didn’t cause a crash. I rely on that.

thanks! yeah, that’s really what brought this whole rant up. Obj-C just kept on biting me with this “calls to nil work” thing. some other arguments have been brought up in other comments, but i just don’t buy them. for me, messages to nil really should fail.

The thing is, though, it’s

The thing is, though, it’s very rarely an issue that nils propagate. Because most of the time, it will be obvious where a nil somewhere up the chain came from. And pretty quickly you’ll try to use the nil value as an argument and not as a message recipient, and then an exception will likely be raised. You can’t addObject:nil, for instance, that will raise an exception.

In practice, you do not run into problems with this. You need to make a small adjustment in how you approach your code, but this is true of all of Objective-C: You really do need to get used to it, and then it will work just as well or better than what you were used to before. It is quite normal to be annoyed with it at first, but this usually passes.

(For instance, you quickly learn that it’s useful to let nils propagate when trying to grab a specific object buried inside several calls to different objects, and when you’re done you can do a manual check to see if it is nil or not, instead of having to check at each stage, or having to catch exceptions for the whole thing.)

good to know

that’s great feedback. thanks for that.

In practice, you do not run into problems with this. You need to make a small adjustment in how you approach your code, but this is true of all of Objective-C: You really do need to get used to it, and then it will work just as well or better than what you were used to before.

i’m willing to take a little on faith. and as with any new language feature, i don’t expect that i’m using it properly right off the bat. but it’s so counter to what i consider best practices, it makes me really uncomfortable, gives me less confidence that i understand my code, and generally makes my life harder, at least right now.

It is quite normal to be annoyed with it at first, but this usually passes.

haha good. i am, and i hope it does. :)

(For instance, you quickly learn that it’s useful to let nils propagate when trying to grab a specific object buried inside several calls to different objects, and when you’re done you can do a manual check to see if it is nil or not, instead of having to check at each stage, or having to catch exceptions for the whole thing.)

thanks in particular for this very specific advice. i’ll be sure to try it out soon!

Java?

Failing fast is great. Sometimes a language or API can prevent an error from ever being made, sometimes it can show you the error at compile time, sometimes it can tell you where it happened at runtime, sometimes you’re just notified that there’s an error “somewhere”, and sometimes the only way you’ll know that there is an error is because the result is wrong.

Objective C is in the last category when it comes to null, but Java is not much better - it is in the second last category. Null can easily propagate through anywhere it isn’t directly used, and the path it propagates through is not visible to the programmer. When you get a NullPointerException, the stack trace is often useless because it doesn’t tell you where the null came from.

Languages like SML and Haskell have the Option type that is either Some v where v is the value or None if there is no value. The type system requires you to explicitly handle both cases anywhere you use the option type (or at least explicitly say that you won’t). None is never implicitly propagated. You get your errors at compile time.

Java Primitives?

i think it’s worth bringing up that nulls can’t flow through Java primitive types, but you bring up an interesting point about Java null and reference variables. null can be used any place there’s an object reference is expected, so a null value definitely can propagate through a program. however, because dereferencing null always raises an error in Java, i would claim that you’re likely to discover an unexpected null quickly in most cases. that seems to be the case for me, although my claim is certainly anecdotal.

you’ll hear no argument from me that Haskell’s type system is powerful and elegant! but i do think that comparison is apple’s and oranges. Haskell’s Maybe type (the None or Just value bit that i think you’re discussing above) comes into play only very rarely in Haskell because of it’s functional and referentially-transparent nature. when everything is an expression and nothing is stateful (so there are no variables or assignments), you just don’t run into the need for null values very often. the issue don’t matter in Haskell, by design, whereas tripping over nulls is an everyday occurrence in more conventional languages like Objective-C and Java.

maybe that proves your point, but i don’t think Haskell is The Right Tool for a lot of places that Java and friends go, so i think that’s worth weighing, too.

Java without null

In my experience, the vast majority of fields and variables are conceptually not nullable in Java programs. The type system of Java already makes it easy to implement an Option type, but it would be almost useless when all libraries return and expect null anyway. I think that if Java had had the Option type instead of null from the beginning, then that part would work just as well as it does in SML and Haskell.

Post new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.