3 ms·
This is a step in the right direction. C++ exceptions in practice are difficult to get right, and depending on dynamic allocation in an exception seems problema
by getpost 8y ago
This is a step in the right direction. C++ exceptions in practice are difficult to get right, and depending on dynamic allocation in an exception seems problematic to me.
One of the main reasons to use exceptions is to save code. In one of my projects, using exceptions instead of checking error returns saved 11% in code size. The exception version of the code was more correct, since there were many fewer places where error codes were handled. The golang people just don't get this.
The subtleties are not longer fresh in my mind, but "throws" rubs me the wrong way. Why declare whether a certain function may throw an exception? The beauty of exceptions is that you can use code that throws exceptions without having to know exactly where exceptions can occur.
- mastax 8y ago> The subtleties are not longer fresh in my mind, but "throws" rubs me the wrong way. Why declare whether a certain function may throw an exception? The beauty of exceptions is that you can use code that throws exceptions without having to know exactly where exceptions can occur. Throwing an exception does not alter the ABI for a function, since the mechanism for throwing exceptions is separate from normal control flow. They call into library code for unwinding the stack. This is what makes them "slow", and it's why they require heap allocation since there's no pre-made place to store the value. Throwing a value (as proposed) does alter the ABI for a function. That value needs a place to go, it's essentially another return value. Removing the requirement to add throws to the declaration would be like allowing these two functions to be the same: int foo(); std::either<int, std::std_error> foo();
- nine_k 8y agoWhy not eschew the idea of "exceptions" at all then, and just return an error outcome if it can be expected? You've just wrote down a way to do that with no ABI changes. A more expensive (and preferably non-allocating) mechanism could be used for a controlled "panic", that is, winding things down in an orderly manner when an unpredictable error occurs.
- mastax 8y agoIt seems a bit like the difference between async fn foo() -> int and fn foo() -> Async<int> (pseudo-rust syntax but the distinction also applies to C# and JS, et. al.) Async code and error handing can both be implented with regular code, but there are cases where some compiler magic can be more elegant, more expressive, or more performant. In these cases it's nice to have a construct that distinguishes this magic from regular values, rather than just making a specific return type magic, IMO. In the throwing values proposal, the magic is to make a regular value usable in exceptions, and also to use mostly-hidden CPU state (flags register) to indicate the type of the value. This allows the C++ proposal to use less memory and perhaps be more performant than rust-style error values. (This ABI change could also be used in other languages like Rust, as mentioned at the end of the document)