JavaScript's untyped function arguments, or: Try...Catch?
Ok, so for a while now I've been woefully undereducated on the uses of try...catch. I know, I know, how can I claim to know JavaScript beyond even a basic level without knowing try...catch. Ok fine, sue me, denounce me as a poser, MEA CULPA. :P
Why is this relevant to the title? Well for a while now I've been manually checking argument type like so:
function doSomething( aJadeObject ){
if( aJadeObject == undefined ){ return; }
if( typeof(aJadeObject.isKindOfClass) != "function" ){ return; }
if( !aJadeObject.isKindOfClass(NecessaryClass) ){ return; }
//blah blah blah...
}
The first line verifies that the argument is defined, because if it's not the second line will destroy the script. The second verifies that the object responds to the JadeObject method that's used to test descent from a particular class. The third actually verifies that descent. I did this for obvious type-checking purposes. I don't want to sent JadeArray query messages to a number or to null and kill the program, do it? No. Instead it would be better if bad messages just returned some default or null value or something, so that in such a case, the program would still function but there would just be a minor, localized, and likely unnoticeable, fault, instead of taking the entire thing down.
This whole convoluted system came up in a discussion with the ever patient Emmanuel Zephyr, my Cocoa devver friend person. I asked him his opinion on what sort of values should be returned when the function by default is supposed to return some none-void value. His suggestion was that i shouldn't even bother with all of that but instead should just use try...catch, which would simply try to perform the necessary operations without crashing the script. If the objects in question respond to the necessary messages then the try block will work successfully, which means that as far as the script cares, the arguments were the right type, otherwise it would fail and no bad things would happen.
So instead of all of that junk above, it would reduce to...
function doSomething( aJadeObject ){
try {
//blah blah blah...
} catch(e){
//maybe log the error?
}
}
without any type checking at all, and with a potential area for handling these type errors, possibly with some sort of logging for later debugging. I can't really believe that I allowed such a useful tool as try...catch slip past my dradis, but that's life, ey?
My only concern is this:
var x = 0;
try {
x = 5;
y++; // throws an exception because y is undefined
}
alert(x); // alerts 5, because the x = 5 assignment works, despite the try block containing exception-throwing code.
This is potentially problematic because there might be cases where something is added to an array or whatever on the assumption that it's a certain type of object, and then it gets sent a message that it doesn't know how to respond to because it's not that type of object. So now the try fails but the object is still in the array, which is probably not a good thing. Now, this might not be a huge issue, and any problems that it might cause probably won't be too hard to fix, but it's definitely not perfect. Oh JS2, where art thou?
Comments
1. Check arguments before doing anything else.
2. Use assertion routines that throws an exception if the assertion condition fails
For example:
function doSomething( aJadeObject ){
mustBeDefined(aJadeObject);
//blah blah blah...
}
function mustBeDefined (value) {
if (value == undefined) {
throw new Error(0, 'Value must be defined');
}
}
That is exactly why I don't use try catch for everything, type checking is more sane.