Reputation: 755
I'm reading chapter 8 "Bugs and Error Handling" from Eloquent JavaScript. I came across with an example about a wrong code but I still don't catch at all the explanation the author gives about what causes the failure. Let's give the context: in section "Selective Catching" the author says:
Invalid uses of the language, such as referencing a nonexistent variable, looking up a property on null, or calling something that’s not a function, will also result in exceptions being raised. Such exceptions can be caught just like your own exceptions.
When a catch body is entered, all we know is that something in our try body caused an exception. But we don’t know what, or which exception it caused.
JavaScript (in a rather glaring omission) doesn’t provide direct support for selectively catching exceptions: either you catch them all or you don’t catch any. This makes it very easy to assume that the exception you get is the one you were thinking about when you wrote the catch block.
But it might not be. Some other assumption might be violated, or you might have introduced a bug somewhere that is causing an exception. Here is an example, which attempts to keep on calling promptDirection until it gets a valid answer:
for (;;) {
try {
var dir = promtDirection("Where?"); // ← typo!
console.log("You chose ", dir);
break;
} catch (e) {
console.log("Not a valid direction. Try again.");
}
}
The for (;;) construct is a way to intentionally create a loop that doesn’t terminate on its own. We break out of the loop only when a valid direction is given. But we misspelled promptDirection, which will result in an “undefined variable” error. Because the catch block completely ignores its exception value (e), assuming it knows what the problem is, it wrongly treats the variable error as indicating bad input. Not only does this cause an infinite loop, but it also “buries” the useful error message about the misspelled variable.
I think I don't get the explanation because Enlgish is not my native language. What I don't get is the bold sentence. I don't understant why the catch block does ignores variable e and the thing about the bad input. Does catch block assume that e is a bad input?
Could someone clarify me this, please. Thanks in advance.
Upvotes: 2
Views: 1300
Reputation: 5510
The point that the author is trying to make, is that it matters how you set up your error handling. Let's assume that one of the goals of building error handling into your program is to make it easier to catch and solve bugs when they emerge.
Well if that is the case, then what what the author is illustrating here is that this is an example of error handling that hides the real problem, making the bug actually harder.
How is it hiding the problem? Well if you look at the code there it nicely sets up a try
block. But then in the catch
statement it doesn't bother ever to check to see what kind of error has been caught. It just assumes that the error that's been thrown is always related to an invalid direction.
But that's not the case! Because as the author tells you, the function name is actually misspelled, which will trigger an "undefined variable" error. However, because catch block doesn't bother to check the attributes of error e
, the user will never know that that is the error that occurred. Instead they will always see "Not a valid direction. Try again." But that's actually wrong in the case where there's an "undefined variable" error. Rather than the problem stemming from incorrect user input, the problem is in the code itself! This example is particularly bad, in fact, because the coder's error will look like a user error.
So how would we do this the right way? Well, there are a number of ways. The easiest thing would be to make the output to the console indicate the error that has been thrown, like so:
for (;;) {
try {
var dir = promtDirection("Where?"); // ← typo!
console.log("You chose ", dir);
break;
} catch (e) {
console.log(e.name, ': ', e.msg);
}
}
Better yet, let's say that our promptDirection
function can throw a custom error, that looks like this:
function InvalidDirectionError(message) {
this.name = 'InvalidDirectionError';
this.message = message || 'Not a valid direction. Try again.';
this.stack = (new Error()).stack;
}
InvalidDirectionError.prototype = Object.create(Error.prototype);
InvalidDirectionError.prototype.constructor = InvalidDirectionError;
then in our catch statement we could do:
for (;;) {
try {
var dir = promtDirection("Where?"); // ← typo!
console.log("You chose ", dir);
break;
} catch (e) {
if (e.name == 'InvalidDirectionError') {
console.log(e.msg);
} else {
console.log(e.name, ': ', e.msg);
}
}
}
I hope this helps. Please comment if you need further clarification.
Upvotes: 2
Reputation: 115950
The assumption here is that promptDirection
sometimes raises an error as part of its normal operation, when its input is not valid. This code is supposed to catch the error thrown on invalid input. Imagine it's something like:
function promptDirection(text) {
var value = prompt(text);
if(value != "up" && value != "down") {
throw new Error("not a valid direction");
}
return value;
}
However, promptDirection
here is misspelled as promtDirection
:
But we misspelled promptDirection, which will result in an “undefined variable” error.
Thus, the code will always raise an error, which is not what the hypothetical author intended (i.e., that errors are raised only on invalid input).
You could use e
to test for the expected type of error:
catch(e) {
if(e.message == "not a valid direction") {
console.log("Not a valid direction. Try again.");
} else {
console.log("Something else went wrong:" + e.message);
}
}
Upvotes: 3
Reputation: 37803
The author isn't saying JavaScript always ignores e
; he's talking about this specific example. This example code is written badly (on purpose):
catch (e) {
console.log("Not a valid direction. Try again.");
}
We catch an exception (called e
) but we don't ever try to figure out what kind of exception. We just always, always say "Not a valid direction. Try again."
This code is assuming that there's only one thing that could go wrong: the input isn't valid.
Upvotes: 3