4 ms·
Returning an option sumtype is also typesafe. Exceptions have to walk up the stack until a suitable handler is found, that handler can't know ahead of time whe
by bhawks 4y ago
Returning an option sumtype is also typesafe.
Exceptions have to walk up the stack until a suitable handler is found, that handler can't know ahead of time where the value is coming from or if it will ever arrive - just what type it will be if it arrives. Code emitting exceptions also have no knowledge who (if anyone) is going to handle their output. It is a nonlocal goto in reverse.
Compared to regular functional returns there are so many unknowns. I'd prefer returning an option value any day of the week.
- cobbal 4y agoThat's one way to compile exceptions. There are other methods with different tradeoffs for different cases.
- tsimionescu 4y ago> Code emitting exceptions also have no knowledge who (if anyone) is going to handle their output. This is no different from code returning a regular value. When writing `return -EINVAL;` or `return 0, fmt.Errorf("")` or `return Err(something)`, you have no idea who (if anyone) is going to handle your output. Also, one reasonable way of implementing exceptions could be exactly to translate all functions that can throw exceptions to functions returning a Result type, and translating function calls to such functions to the equivalent of pattern matching on that return. Of course, this mostly forces the language to only support checked exceptions (otherwise this overhead would be added to all function calls, even those that can't actually fail). Most languages that implement exceptions have chosen a different trade-off though: make exceptions costly to throw, but make sure they have 0 cost on the happy path. Happy-path code becomes more efficient than it is possible to be in a language which uses return values for errors (since there is no need to check the result before using it), but the unhappy path becomes significantly worse.
- bhawks 4y agoA normal function return is handled directly by the caller, even if the caller decides to completely ignore it. In the case of exceptions it continues to implicitly pop the stack to attempt to find a handler. The explicit vs implicit nature is quite different. I'd also point out that in gcc and clang support nodiscard and warn_unused_result giving a function some ability to force callers to handle returns. Go, rust and even java (thanks to errorprone) have similar guardrails. I think you also need to balance the marginal efficiency wins of not checking for errors on return with the overall robustness of your program. The likelihood that an error condition is properly handled is heavily predicated on your ability to know that it might occur in the first place. In a language where exceptions are common place make this very challenging because they heavily rely on unchecked exceptions. Languages that value error checking have tended to shun exception style in favor of returning option types.
- gpderetta 4y ago> one reasonable way of implementing exceptions could be exactly to translate all functions that can throw exceptions to functions returning a Result type, and translating function calls to such functions to the equivalent of pattern matching on that return That's exactly what the lightweight exception proposal for C++ argued for. It additionally used some ABI tricks like storing the discriminant in a flag register when returning from an exception throwing function allowing for very cheap and compact pattern matching.