Exceptional Situations Require Exceptional MeasuresSubmitted by Matthew Turland on Wed, 02/04/2009 - 16:10
"Extreme situations require extreme measures." If you are or used to be a fan of the Karate Kid movies, you probably recognize that quote. I see some similarity in this quote from Andy Hunt and Dave Thomas originally stated in Chapter 4 Section 24 of The Pragmatic Programmer: "Use exceptions for exceptional cases."
Davey Shafik, who I consider to be a professional colleague and a personal friend, recently got back to blogging. He's been known to have several opinions on the matter of API design. Upon reading one of his latest posts, I was rather surprised (as it rarely happens) that I disagreed with him.
Within the context of semantics as the term applies to computer science, I think the boolean data type continues to exist for the same reason that invoked its creation: to indicate the truth value of a logical condition. To put this another way, a function should return a boolean value only if the purpose of that function is to check the truth value of a condition and return a boolean value appropriate for the condition's state. If a function is well-named and begins with "is" or "has", in the absence of its source code or any accompanying comments that might be present, it is intuitive to presume that the function returns a boolean value.
Taking Davey's example, let's say that you have a function for which the purpose is to return a data set. There are two possibilities with regard to the application requirements: the function may return data or the function must return data. If the function may return data, an empty array is a perfectly legitimate return value. If the function must return data and it does not, this is an exceptional case that should not occur and may indicate an underlying issue with the application. At that point, I know I'd rather the application terminate its current line of execution (before it makes a mess that I'll have to clean up later) and perform some sort of logic to notify me of the issue that occurred. I'd want it to do so regardless of the specific type of issue because no matter how you slice it, it's still an exceptional case.
I have no doubt that the identical comparison operator was at least partly intended as a solution for the perceived problem that dynamic typing rendered some function return values ambiguous. You only need to look as far as the strpos function page in the PHP manual to read that for yourself. The purpose of that particular function is to return the position of a substring within a string and it fulfills that purpose well. However, it's used just as often (if not more so) to check for the mere presence of the substring, when the specific return value is irrelevant so long as it indicates presence or absence.
The multipurpose application of the function is what makes its return value ambiguous and the identical operator just a band-aid in that situation. What alternatives are there, you're probably asking? I can think of two: 1) a parameter for a callback to execute; or 2) a boolean value indicating that an exception should be thrown when the absence edge case occurs and it's relevant to the application requirements. A boolean value used to indicate error is really nothing but a digest version of the error code systems of old for which Refactoring has a specific case.
PHP is what it is: a ball of nails. It was organically grown, to borrow a metaphor from Chapter 2 Section 3 "Common Software Metaphors" of Code Complete. It doesn't have a language specification and probably never will. It's likely to have the lower-level pieces of anything you may want to build, but it's certainly not without what some consider to be blemishes. In my opinion, functions that do things like this are one of said blemishes and their (mis)use of the dynamic typing system yields a bad code smell. Behavioral patterns like this should be hidden in encapsulation and handled cleanly at higher levels, not encouraged for use in userland code of new applications.