3 ms·
At the limit, you can make Result<T,E> very cheap: with a specifically designed ABI you just need a bit in the flags register and a single (predictable) conditi
by gpderetta 2y ago
At the limit, you can make Result<T,E> very cheap: with a specifically designed ABI you just need a bit in the flags register and a single (predictable) conditional jump on the return path (see for example the Herbceptions papers).
At the limit limit, there is no difference between Result<T,E> and checked exceptions, with enough syntactic sugar they can be equivalent both semantically and syntactically [1].
[1] One advantage of typical C++ exceptions implementations, is that if the exception is not caught the stack is not unwound and the stack trace is preserved in the core file. In principle the same thing could be done for Result.
- bluGill 2y agoWith an exception (not checked exceptions) you get the advantage of the compiler knows about this and can optimize some code paths - any function that doesn't handle the function or have clean up to do can be bypassed, while result/checked exceptions need to go into that function anyway - which may be faster, more benchmarks needed. (though is possible a "sufficiently smart" compiler could understand thus pattern and turn it into an exception). So the real question is syntax - which do you prefer: having to write some result type all over instead of the regular return type you mean, or knowing that "magically" at unpredictable times your function will just abort in the middle. There are pros and cons to both, so anyone arguing absolutely for either side is wrong - at least now when we don't have decades of experience with result in large projects (though maybe we do in a single project)
- gpderetta 2y ago> With an exception (not checked exceptions) you get the advantage of the compiler knows about this and can optimize some code paths while result/checked exceptions need to go into that function anyway. Once you convert them in CPS form there is really no difference between the two. In principle you could compile both to exactly the same code. [edit: also not sure why are you singling out checked exceptions] [edit: specifically you could compile any code that returns an Either to a function that takes two return continuations instead of just one, and in CPS form exception-like non-local exits are trivial] Of course in practice traditional procedural languages do not compile through CPS and use abnormal edges in basic blocks to represent exceptions. > There are pros and cons to both, so anyone arguing absolutely for either side is wrong I'm in the camp that, in a well designed language[1], there would be no difference between the two :D [1] according to my personal preferences that I can assure you are completely objective!
- kllrnohj 2y ago> At the limit limit, there is no difference between Result<T,E> and checked exceptions How do you figure? A Result<T,E> always means a branch after function calls, while checked exceptions have no such cost. Toy example: https://godbolt.org/z/Gqo9n17c6 https://godbolt.org/z/Gqo9n17c6 It's trivially observed that exceptions simply have less code in the normal path. There's no post-call checking for errors, which is of course present in the Result<T,E> approach. And even where the exception is caught, that's not part of the "hot loop". It's not executed at all normally. Unwinding exceptions are completely free when they don't happen. The same is simply not true and never can be true of a return-value based propagation.
- gpderetta 2y agoSee my other comment.
- saurik 2y ago"At the limit limit," you can detect the unstructured branches littered through the codebase of people using Result and convert it all into clean structured exceptions, and even automatically remove all the boilerplate this paradigm uses to propagate errors; this is at least a reasonable thought process due to the same reason you can (much more trivially) implement your exception mechanism by burning a return register for an error code and compiling in a ton of branches (which isn't insane if you in fact want to throw an error often: this is all just a tradeoff that Rust made awkward and its community turned into a religious war). It isn't easy, though, as the Rust way of doing this--letting people pass around a bare Result without the structure of a monad (which is why Haskell's version of this idea looks like exceptions, and why it is so frustrating when people incorrectly claim Rust has "monadic" error handling)--makes it extremely easy to pull off what should be "stunts", such as holding onto a Result and trying to resolve them in an irreducible order; but, "hopefully", most code isn't making that mistake (and you can still implement it by adding a spurious expensive catch in just the places they did that)... but like, that's why I think the person you are responding to might have said "at the limit limit", to really emphasize that this is a pretty complicated reduction to automatically apply globally and truly result in 0 cost.