Re:Current hardware trends make C++ exceptions harder to jus...
by ncmncm on Wednesday February 23, 2022 @12:47AM
(#30438078)
Any exception thrown in response to a bug is a fundamental design failure.
At the point where it is evident the program has a bug, there is nothing known, anymore, about the state of the program. It means that data structures defining the state are inconsistent to a wholly unknown degree, and any further computation depending on or,worse, altering that state can do no better than compound the failure.
I always delete code I find that tries to recover from a bug. It is impossible to recover from a bug; the best that can be done is to bail out as fast as possible.
Re:Current hardware trends make C++ exceptions harder to jus...
by hashmash on Tuesday February 22, 2022 @06:14PM
(#30435214)
The problem that you outlined is a different one than whether or not exceptions are checked. The further an exception is thrown (call chain depth), the more context that gets lost. This can be fixed with more specialized exception types.
My example of declaring an NPE as checked isn't something I would actually encourage. It conveys very little context, and exceptions which extend RE should signal a bug in the code. I should have selected a better example.
Re:Current hardware trends make C++ exceptions harder to jus...
by layer8 on Tuesday February 22, 2022 @09:01PM
(#30436665)
The problem is strongly tied to whether exceptions are checked if you want to have the type system support you in checking and validating your reasoning about the contracts between callers and callees. With unchecked exceptions, unless you have extreme discipline and document exception types for every function, and take care to use dedicated exception types for all non-bug exceptions, effectively emulating what the type-checker does for you with checked exceptions; unless you do all that, it's a fool's errand in terms of ensuring (being able to prove the correctness of) your interface contracts.
I understand your point about usage-dependend checking. However, I believe it is mistaken. Consider a call chain A -> B -> C -> D, where D throws a checked exception of type X, which C converts into an unchecked exception (still type X). At the same time, B also calls other methods that happen to throw a checked X, and thus B throws a checked X itself, which now, unbeknownst to B, also includes the X from D. B documents the semantic of its X exception, which may not fit the ones thrown by D. Now A catches X, believing the semantics as documented by B, but actually also catches X from D, which was concealed (made unchecked) by C. This breaks checked exceptions in their role as part of an interface contract.
The fact that unchecked exception may originate from arbitrarily deep in the call chain is also the reason why they are unsuitable for defining interface contracts, A function declaring certain semantics for a particular unchecked exception can't realistically ensure those semantics if any function it calls itself must be assumed to also throw exceptions of that type (because it is unchecked). Effectively, you can't safely document "exception X means condition Y" for your function if any nested calls may also throw X for unknown reasons.