# Refining Absolute Rules

In the book Code Complete, the author asserts that functions which were expected to compute a value may only fail in one of three ways: They may throw an exception, they may return null, or they may return an [[Inert Value]]. An inert value being a value of the expected type, but which is not considered to result in meaningful execution. If the function was expected to return an array of values, an empty array might be considered inert.

Drive home the idea of an "absolute" rule—a rule without padding.

Most absolute rules like this start from a simple realization. In this case, the author might have realized that failure is only handled in a few distinct ways. From here, a question should be formed to define the boundaries of the realization. In this case, the question would be "how many distinct ways are there to handle failure in a function that is expected to compute a value?"

It's important that your questioned be formed in a way such that the answer will be limited in scope. Otherwise you can't be confident in an absolute rule. If a question is too broad, like "how many different ways are there to produce a pseudo-random value," (hint: infinitely many ways) then you cannot form a sure answer. Only a partial answer, and those are less helpful.

A question that is limited in scope allows for the next step: exhaustive discovery. It is likely that you will already have an answer in mind, but does that answer cover the entire scope of the question? Let's look at our working rule. If a function fails, the only way that it is allowed to exit without returning a value is to throw an exception (or an equivalent action in a language that doesn't have exceptions).

If the function doesn't throw an exception, then it must return a value, but if the function failed to find the correct result, then it must come up with an alternative. Null is an obvious option, but we would need to extend it to include other null-like values, same as we extended "exceptions" to include any halt in execution. The term "null value" could be extended to include any result that exists outside the solution space. If the function was expected to return a number, NaN, short for Not a Number, is a null value. In fact, this is often the result of undefined mathematical operations, like division by zero.

The last option is to select an inert value, a value which is in the solution space, but is not expected to result in meaningful execution. For numbers, this might be zero, negative one, or infinity depending on the context of the caller. This third option might have been missed if we were relying on our intuition alone, but our question and answer approach allows us to be exhaustive. Once we've considered exceptions—any halt in execution—and null values—any return value outside the solution space—we could ask ourselves a more specific question: Is there an incorrect result we could return which is inside the solution space? The answer is yes—inert values.

Go back and generalize Exceptions to cover any halt in execution and null values to cover any return value outside of the solution space.

At this point, we could try our scope trick one more time to see if we could spot a fourth solution. Is there an incorrect result we could return which is inside the solution space. The answer is, yet again, yes. Imagine a video game routine which is expected to return an item list for a chest that the player just opened. The item selection might be based on the context of the dungeon, the difficulty of the boss, the characters level, and even the mods the character has installed. If this function fails to find a competent item list, it could rely on a fallback of gems and gold. This isn't an inert value, as the result is as meaningful to execution as any other item, which implies that we might have found a new failure option.

At this point, we need to decide whether or not to extend the scope of Inert Values, as we did with Null values and NaN. Or if we should add a new entry to our rule, and just say that a simpler but more meaningful Fallback Value is one way of handling failure. Or we could see this as not a failure at all. Even if simple gems and gold isn't an optimal result, it is still a result. If that result isn't considered a failure then it doesn't meet our original question, which only referred to handling failure.

For the sake of being conclusive, we're not going to include Fallback values. Otherwise we'd need to keep this process going, and there's no end to fallback computation.

The author presented his rule very confidently, as he should. How else could a computation fail? Halting execution in response to failure is, by definition, an exception (or at least equivalent to an exception). If the function fails to throw an exception, then it must complete execution, which requires that it return some value. The only two types of values that a failed function could return are a null value or an inert value.

1. Invent a question with appears to have an answer bounded by some scope.
2. Attempt to answer the question, at least partially.