One problem is that some platforms/libraries use special properties on the error object instead of subclasses to make different error types (like node), so you would also need to provide a way to support them too. I had previously proposed providing a standard exception class to Javascript, which if used would make this kind of feature more palatable. The consensus in that proposal is that the design I came us with would probably break backwards compatibility, but it could still be possible to get everyone to use a standard system through a protocol, i.e. if an exception provided a unique key to a Symbol.exceptionType property (or just a non-symbol "code" property), and the catch clause would could check against a key. For example:
DOMException[Symbol.exceptionType] = 'DOM:DOMException'
try {
doSomeDomOperation()
} catch 'DOM:DOMException' (ex) {
console.log('A DOM exception was thrown!')
}
If we don't get everyone onto a standard, then your catch handler would need to be flexible enough to handle exception subtypes and unique properties on the error object. Here's one possibility:
const isSubType = type => ex => ex instanceof type
const hasProperty = (key, value) => ex => ex[key] === value
try {
...
} catch where isSubType(DOMException) {
...
} catch where hasProperty('code', 'FileNotFound') {
...
}
You don't need to limit yourself to instanceof. You could make catch accept any expression (where the exception would be bound to a fixed identifier, e.g. error or exc). The current form with a single name would be unaffected.
Or, you could replace catch with match:
try {
...
} match (ex) { // binds just like `catch (ex)`
// but here you do pattern matching
}
Yes, but take node for example. They don't subclass their fs errors, instead, they throw a regular error object and add a "code" property to them that explains what went wrong. For example, here's how you would handle a file-not-found error in node:
try {
fs.readFileSync(...)
} catch (ex) {
if (ex.code === 'ENOENT') {
...
} else throw ex
}
Javascript has never officially declared that "subclassing exceptions is the way to go", so many people do it in different ways, and we need to be conscientious about the different solutions out there when we make a catch handler. Our options are to either to make this syntax support all options, or provide a non-backwards-compatible-breaking path for library implementers to use, that would unify the different types of exceptions (such as, asking people to provide a unique value for their exception in a symbol).
@lightmare - the pattern-matching-catch thing is a good idea too. For reference, the pattern matching proposal actually shares almost exactly that as a potential solution to this problem, that could maybe be done in a follow-on proposal. See here.
And here's their code example:
try {
throw new TypeError('a');
} catch match (e) {
if (e instanceof RangeError) { β¦ }
when (/^abc$/) { β¦ }
else { throw e; } // default behavior
}
The problem I see with catch (someFunction) is that now you don't have a place to bind the thrown error to a variable, so such a function would need to be placed elsewhere, e.g. catch when someFunction (err)
If an error gets thrown inside the predicate, I'm not too concerned about what gets thrown from it, as long as something useful does. Such an error would only be caught or reported for debugging purposes, it's not something that should be recovered from. So, it could be that we bail the try-catch and let the error from the predicate be what get's propagated (similar to what happens when an error is thrown in a finally block). Or, we could throw an aggregate error containing both the original error and the error from the predicate. Either way works.
That said ljharb's comment is why I haven't moved it outside the future consideration notes. Being able to throw in the "when" part complicates things. Can return false or throw outside of the try. I don't even know what C# does in these cases.
It should be the same thing that happens when a normal catch throws. Remember that this is just candy for having exception type checking in the catch body.
For this, there would be a few syntax restrictions, namely that the function must be an arrow function with no parenthesis for the single required parameter and a single non-block expression for the function body. The parameter variable would be passed on to the catch body.