In older procedural languages, the return values that came back from a function were restricted. If you said you were going to return a number, you returned a number. If you wanted to sometimes return a number, but other times return an indication of failure, you resorted to what is known as a “sentinel value” to return the failure.
A sentinel value is a number that doesn’t represent the answer to the problem that the function was asked to solve, but instead flags the caller to the fact that something rather out-of-the-ordinary has happened. For example, a value of -1 can indicate the end of a file being read in.
The problem with a sentinel is that it means nothing special to the language. The programmer has to keep in mind that the sentinel exists and that it has to be handled on every call that could possibly generate the sentinel value. Programmers are notorious for paying attention to and handling sentinels only when they crash a program.
Also, the programmer has to be careful in choosing the value. Is it 0? -1? 99? 255? 999? -999? MAXINT? The choice can bite you if you’ve misunderstood the possible values that can be generated in your function. I regret to inform you that I once wrote a BASIC program that had three different sentinel values returned from three different subroutines!
Sentinel values sound old and busted, don’t they? Their usage fell a bit once we could pass around pointers to data structures. With a little more elbow room, we could put a “success” boolean right up front in the data structure and do away with a lot of sentinels.
They Live!
But sentinels are still around. In JavaScript, the string method “indexOf” returns a -1 if the needle (substring) can’t be found in the haystack (the string to be searched).
Let’s look at a few different ways we can deal with that awkward -1.
function wrappedIndexOf(needle,haystack) { var res=haystack.indexOf(needle); if (res===-1) { res=false; } return res; }
And you call it like this:
res=wrappedIndexOf(needle,haystack); if (res!==false) { location=res; }
We haven’t done much here but replace the need to check explicitly for -1 with a need to check explicitly for false. Too weird to sometimes return a number and sometimes return a boolean? Yeah, probably. I like it a bit better than the numeric sentinel because the calling code makes the exception check a bit more obvious. Because JavaScript functions can return just about anything (including wild things like anonymous functions), you always need to think about what can come out of a function, so what’s important is a consistent convention.
Similarly, you could return null or undefined.
But let’s move on to another solution–returning an object.
function wrappedIndexOf(needle,haystack) { var res=haystack.indexOf(needle); if (res===-1) { res={"success":false,"value":-1}; } else { res={"success":true,"value":res}; } return res; }
And you call it like this:
obj=wrappedIndexOf(needle,haystack); if (obj.success) { location=obj.value; }
Note that I’ve left the -1 in obj.value, so you can still use that as a sentinel if you like.
What makes JavaScript really good for this task? Its object literals. You don’t need to have a structure or class around to hold the extra info. You just build the object on the fly and return it.