6 ms·
> Exceptions imply a temporal coupling from error occurrence to error handling. Could you expand on this? I understood your statement as "Exceptions sort-of fo
by uryga 8y ago
> Exceptions imply a temporal coupling from error occurrence to error handling.
Could you expand on this? I understood your statement as "Exceptions sort-of force you to handle an error the moment it occurs", but I'm having trouble seeing why this would be specific to exceptions and not the case with other error handling solutions.
(I don't mean to sound like a big exception-defender – I prefer ML/Rust-style Result types)
- gbear605 8y agoA rather odd example with Result type systems: Say you have a function that returns the results of three other functions together in a tuple and the first one errors. The other two can still run and their result can be returned in the tuple along with an Error for the first function.
- uryga 8y agoAh, so using Result types you can return `(Optional<A>, Optional<B>, Optional<C>)` – each can fail or succeed independently. But you can't do that if you're using exceptions to signal errors – it's like returning `Optional<(A, B, C)>` , you get either all the results or nothing. Good example, thanks!
- Jtsummers 8y agoYou can still get something like that using exceptions, it depends on where the exceptions are caught. If you have a function which has 3 calls: function f (...) { val a = something.a(); val b = something.b(); val c = something.c(); return (a,b,c); } If the exceptions can occur in the calls assigning to a, b, or c and are handled locally (here, in f) then you can construct that first case. It's only if you throw the exception up one level higher that you end up in the latter case. As written, it is more like your latter example. But with a modication: function f(...) { val a = default_a; val b = default_b; val c = default_c; try { a = something.a(); } catch { a = error_value_a; } ... } You can get the former case.
- jstimpfle 8y agoIn some cases immediate action might have to be taken (like calling abort()) but very often that is not the case. Another strategy is to collect errors. Then decide what to do them at another point (no temporal or physical coupling!). After all errors are collected, you can group them, sort them, or aggregate them. Whatever is appropriate. Looking at errors as just data avoids the "exceptional vs non-exceptional" hair splitting, and gives a lot of flexibility for code structure. I don't necessarily disagree with the Result type viewpoint as a return type from functions, but I also find it pretty pointless. Very often the best action is to separate out errors from successes into different tables immediately. A built-in Result type couples them, and encourages keeping them coupled. Now you could argue that you can do that with Exceptions, too, by catching them immediately and treating them as data. In which case I want to ask "what's the point then?" and also refer to my topmost comment. Exceptions have a significant cost in infrastructure even if you don't actually use them...
- gdy 8y agoWhat are you going to do with the errors once you have collected them? What is the point of sorting or grouping them?
- jstimpfle 8y agoA simple example from the compiler I'm working on right now: I output type errors of expressions sorted by their location in the source file, instead of in the order they are detected. I also don't error out on the first one, but find all at once. I could also group warnings and errors together, output only the first N errors, or... whatever I fancy. Errors are just data.
- gdy 8y agoWell, this example seems somewhat contrived to me because these errors are not the errors happening in the compiler, they are diagnostic messages describing the errors in the input data. Any chance you have another example?