4 ms·
> If instead you have 11 states because all your variables are actually unions with an error, that's 11^3 states (assuming all error states are equivalent to a
by anonymoushn 4y ago
> If instead you have 11 states because all your variables are actually unions with an error, that's 11^3 states (assuming all error states are equivalent to a single state).
This isn't what actually happens though, what actually happens is that people declare local and member variables that are the_type_i_actually_want instead of Result<err, the_type_i_actually_want> and bubble up their errors like they would exceptions. So they get the benefits that you've claimed, but they don't need to pay the runtime cost of not-thrown exceptions that C++ users have to pay, they don't have to use external tools to tell them that functions they're using can throw exceptions, and they don't have to enjoy the wonders of Java where checked exceptions in function signatures regularly prevent the use of streams.
- menaerus 4y agoYou're conflating recoverable errors (Result in Rust, status codes or std::expected in C++) with the non-recoverable errors (panic in Rust, exceptions in C++). If we were to compare Rust panics vs C++ exceptions, then handling of Rust panics is much less flexible. From what I understand, it's essentially a std::abort and it can be hardly used otherwise, which is only a subset of how C++ exceptions can be commonly used too. If we were to compare Rust Result vs C++ std::expected, they boil down to pretty much the same with the difference of Rust requiring the call-site to unconditionally check for the return value. That may or may not be preferable in every situation. > they don't need to pay the runtime cost of not-thrown exceptions that C++ users have to pay Had this been true, which in 99% of cases it isn't unless you can support your claim, do you mind sharing how Rust implemented their zero-cost panics?
- ginsider_oaks 4y agoThey're not conflating. mgaunard says: > The alternative that the parent said was making all of your state be a union > with some kind of error, and making sure all accesses handle the fact the > variable might be in a erroneous state. This is exactly what `Result` is in Rust. While I haven't used Rust, it seems that panics are generally discouraged and only used as a last resort whereas exceptions are more commonly used in C++ and Java.
- menaerus 4y agoYes, they are. They are basing their argument by comparing Rust Result against C++ exceptions in the context of general error handling whereas I pointed out that there are actually two classes of errors and both of which are addressed their own appropriate mechanisms in both Rust and C++. What parent comment tried to (wrongly) imply, and your comment as well, is that exceptions in C++ are (commonly) used as a control flow mechanism. And they are not.
- mgaunard 4y agoThere is no cost to exceptions that are not thrown. On the contrary, the approach you describe introduce a lot of overhead, since it affects all code paths, the function call ABI, jumps after every function call etc. Also in C++ you have operators that are integrated in the type system and are resolved at compile-time to know whether an given expression can throw an exception or not. Do not confuse C++ with Java.
- anonymoushn 4y ago> There is no cost to exceptions that are not thrown. This is not true for a variety of reasons, but the main ones are maybe missed optimizations and otherwise-unnecessary spills of objects into memory so that their destructors may be called. > Also in C++ you have operators that are integrated in the type system and are resolved at compile-time to know whether an given expression can throw an exception or not. Maybe if you only have a single TU or LTO? In general any function from another TU can throw an exception so you don't have this.
- mgaunard 4y ago> This is not true for a variety of reasons, but the main ones are maybe missed optimizations and otherwise-unnecessary spills of objects into memory so that their destructors may be called. The missed optimization opportunity you describe only affects the Windows ABI, designed in 1989. > Maybe if you only have a single TU or LTO? Whether a function can throw or not is part of its signature.
- marcosdumay 4y agoYeah, that's why exceptions were created back then. They got rid of a lot of extraneous branches in exchange for a small, nearly constant cost on your function calls. But with decades gone, things changed. That constant costs is relatively not so small anymore, and those branches are much cheaper now.
- inkyoto 4y ago> There is no cost to exceptions that are not thrown. Oh yes, there is. C++ compiler has to emit unwind tables, register destructors for RAII resources and generate the RTTI information (where applicable). In this trivial example, consider and compare two versions, the first does not have an exception handler, the second one wrap a single constructor call with a dummy try/catch block: – No exception handling: https://godbolt.org/z/MK1bof45d https://godbolt.org/z/MK1bof45d vs – With a dummy try/catch block: https://godbolt.org/z/hT4Efez1h https://godbolt.org/z/hT4Efez1h For the latter one, the object file size is up by 1kB instantly by virtue of adding a no-op exception handler. Exception handling implementation is not standardised and varies across different compilers AND also across different runtimes. Due to space constraints, the C++ exceptions are oftentimes a big no-no in the embedded world due to the space and time cost the language imposes. As well as long gone are the days when a «try» was a «setjmp» plus a few bells and whistles and «throw ecx;» was a «longjmp».