Naming is a strange thing. You take reality, cut a chunk out, assign a sequence of syllables to that chunk, and suddenly you see it everywhere. Having the right chunks named literally changes how you think. In this series of posts, “naming things”, I take some shows-up-everywhere concept from programming (that doesn’t have a name, or that I don’t know the name of) and give it a name. This week’s thing is a property shared by: I call it “fail-useful”, and it is taking what would normally be considered a failure, and redefining it to have a useful meaning. Let’s quickly go over how each of the examples meets that definition. Sending a message to In C++, evaluating In Python, the expression Visual Basic’s notorious In each of these cases, something that would normally have been a failure has been tweaked and re-interpreted into having semantics you can take advantage of. Instead of failing, they’re useful. They’re fail-useful. The main benefit of a fail-useful construct is the ability to implement functionality with it. The resulting code may be more succinct, compared to what failure-handling code would have been. The resulting code can even end up more robust, since it “fails gracefully” in a sense. Fail-useful’s main downside is that it makes it harder to find and fix mistakes. It misinterprets mistakes into “useful” functionality, which puts the program into invalid states and lets it keep going (so it makes things worse and crashes far away from the problem). Sending a message to nil is a feature, not a symptom, so you don’t get warned when it happens by accident. Whether or not these trade-offs are worth it will depend on your application, and your preferences. (I personally prefer to fail fast, but I have to say there’s a certain joy to corner cases lining up perfectly with the way some would-be failure is implicitly handled.) You fail-useful by taking what would have been a failure, and re-interpreting it to have a desirable/useful behavior. — —
Naming Things: Fail-Useful
Redefining Failing
nil
, in Objective-C, does not cause undefined behavior or an exception to be thrown. It simply has no effect, except for returning a default value (typically zero, false, or nil). This allows properly written code to naturally default to doing nothing, like a nil array returning false when you ask if it contains an item and zero when you ask how many items it contains.someStdMap["some_key_not_in_map"]
doesn’t result in an error code being returned or an exception being thrown. Instead a value is constructed, using the appropriate no-argument constructor, and the key is mapped to that value so the operation can succeed. This is handy, for example, if you are counting items (you can just increment itemToCount[item]
, knowing not-yet-seen items will get a default count of zero).list[-1]
does not cause an IndexError
, because it actually means “the last item”. Negative indexes are interpreted as being relative to the end of the list (a restricted form of treating all indexes as being modulo the list’s length), so -1 is only out of range if the list is empty. This often saves you from writing +len(list)
, and combines well with slicing.On Error Resume Next
statement is a way of telling the compiler that, until the current function returns, all errors should be handled by advancing to the next line of code. You might use this in shutdown code, where you want to notify each component of a program to clean up nicely (e.g. flushing streams, closing network sockets) regardless of whether the other components somehow failed at shutting down.Trade-offs
Summary
My Twitter: @CraigGidney
Twisted Oak Studios offers consulting and development on high-tech interactive projects. Check out our portfolio, or Give us a shout if you have anything you think some really rad engineers should help you with.
Archive