3 ms·
Your reasoning is off. You don't have "10^3" states if you always unwrap the return values at the call sites (which implies returning if it fails). It's literal
by jstimpfle 4y ago
Your reasoning is off. You don't have "10^3" states if you always unwrap the return values at the call sites (which implies returning if it fails). It's literally the same as exceptions, just that the errors get encoded by (re-)using the type system. You'll have the exact same types for your local variables -- the only difference being that you would put a '?' (or similar) after function calls, to unwrap the return values.
The advantage of this ADT approach is that you can store error unions more permanently when it makes sense. It is not additional syntax, unlike exceptions. In that sense ADTs are the simpler approach of the two. If there is any "explosion of complexity", then it is exceptions where you get that -- because you have to express your code using multiple mechanisms (types vs exceptions), and possibly have to switch between the two when refactoring.
I say that as someone who doesn't think highly of either approach. In my view, plain error values are fine, there isn't any clever language solution needed. If you find yourself checking return values a lot (as opposed to storing error values in handles and checking them at strategic locations), that can hint an architectural problem.
- mgaunard 4y agoBy unwrapping and returning, you're creating another path down the control flow of your program, which also propagates to your callee, since you have to return an error. Exceptions don't do that, they stop the flow entirely, then match it to a point arbitrarily higher on the stack, and resume after that whole sub-tree has been destructed. They're also much more efficient than branching and maybe returning on the result of every single function call.
- masklinn 4y ago> Exceptions don't do that Exceptions actually do that, except hidden and unsignaled. > They're also much more efficient than branching and maybe returning on the result of every single function call. Not when actually taken.
- dureuill 4y ago> Exceptions actually do that, except hidden and unsignaled. Which IMO is good in exactly one situation: when raising the exception means that the program contains a bug. Using panics (ah sorry... exceptions) in this case is justified as it should be really exceptional (if there is a bug anyway we have more pressing problems than performance) and in the absence of bug if we were to use a Result type it would mean we would have a "BugError" variant that is actually dead code everywhere where the program is not buggy. So in my opinion a correct approach is to unwrap whenever you have an invariant that guarantees that there should be a value, with a panic handler set at the boundary of the logical task to fail the entire logical task in case there is a bug. A logical task can be an asynchronous light task, a thread, or the whole process depending on the situation. I much prefer it not being the whole process when the process is e.g. a web server or a word processor (and the failure occurred somewhere in an ancillary function)
- jstimpfle 4y agoI don't see a reason why the compiler couldn't implement error-sum return values the same way that exceptions are typically implemented (the way you describe). (I don't see why it should, either. The blanket "efficiency" argument is unconvincing to me). Ok, I see one reason: The programmer might want control which implementation is used. That would require an additional mini-feature in the language syntax/function types. But this still wouldn't be an argument for a whole different syntax and forced separate code paths as required for traditional exceptions. And it's theoretic anyway -- I don't think it's important to give the user this "control".