> Well, the wrong thing to do is to have the printing functions throw a NotSupportedException. The app that the user installed on the Xbox was probably tested primarily, if not exclusively, on a PC, where printing is always available. When run on an Xbox, the exception will probably go unhandled, and the app will crash.
Exceptions are such a catastrophically bad idea in almost all cases.
It is absolutely infuriating as a programmer to call a function and not know if it can throw and, if it can, not know what it can throw. It’s a disaster.
I so desperately wish that C++ had Rust’s Result type and pattern matching. std::optional and std::expected are kinda sorta ok, but you really want compiler enforced pattern matching.
Granted, it may not have the annotation but still not throw in reality, but a Rust function can also declare a Result return type but never actually return an error.
> if it can, not know what it can throw
How do you square that with backward compatibility?
If you declare what you can throw, what do you or any of your transitive dependencies do when they want to change their implementation in a way that makes a new error a possibility? Either you shove it all into an UNKNOWN error that you hopefully declared from the get go to be future-proof, or you break all your downstream users every time. So either no compatibility, or over time your API converges to a meaningless UNKNOWN error code for almost everything and a bunch of legacy error codes that are never used.
I’ve never, ever seen a codebase that reliably used noexcept.
boost and Python are my arch-nemesi because they make heavy use of exception errors and it makes the APIs an absolutely miserable nightmare to use.
> How do you square that with backward compatibility?
Huh? The same way normal code handles changing function arguments or return types? I have absolutely never relied on exceptions to “future proof” return error types! Yikes.
The only thing I have ever used exceptions for is to escape bad input/data. It gets trapped internally in the “private” API and same result types are returned through the public API.
I would much rather have a return type of Result<T, Exception const*> than T but also maybe it throws or maybe not and you almost definitely forgot to check which is why people do filthy filthy hacks like the OP article.
> It is absolutely infuriating as a programmer to call a function and not know if it can throw and, if it can, not know what it can throw. It’s a disaster.
Every nontrivial function can fail (in C even a unary operation on an int), it's just a question of whether and how the caller is informed, how easily the failure is to ignore and continue processing in an undefined corrupted state, and what percentage of the code ends up being dead branches for impossible-but-unprovable error paths.
> I so desperately wish that C++ had Rust’s Result type and pattern matching.
I'm a fan of Rust too, but what do you think panic() is?
Rust has no concept of code that always succeeds. It's all-but impossible on current CPUs.
Exceptions are such a catastrophically bad idea in almost all cases.
It is absolutely infuriating as a programmer to call a function and not know if it can throw and, if it can, not know what it can throw. It’s a disaster.
I so desperately wish that C++ had Rust’s Result type and pattern matching. std::optional and std::expected are kinda sorta ok, but you really want compiler enforced pattern matching.
What a tragedy.