← Back to context

Comment by forrestthewoods

14 hours ago

> All else being equal, exceptions make this kind of code better by making it more readable.

I just fundamentally disagree that hidden secret control flow makes code more readable. Well, it may be more readable but it is, imho, significantly less understandable.

There’s a reason that literally no modern systems language has adopted C++ exceptions.

We’re just about at the point of discussing syntactic sugar. So one question is “given current C++ capabilities should you use exceptions or not?”. Another is “should C++ add different sugar for error handling?”. And a third is “should a different language adopt exceptions-like design?”.

Imho a zig or rust like error system with a ? operator to return is vastly superior. Fallibility and control flow is super explicit, obvious, and easy to read.

Current C++ is a little jankier. Designs vary. All have tradeoffs. But imho they are all preferable to secret hidden control flow. So exceptions are, in my lived experience, a strictly inferior choice.

>I just fundamentally disagree that hidden secret control flow makes code more readable. Well, it may be more readable but it is, imho, significantly less understandable.

That's cool. I disagree that the principal control path should be made more difficult to read in favor of having really explicit error handling that doesn't actually do anything. That said, I do like Rust's question mark operator; it's a pretty cool middle ground between exceptions and error codes.

So, about that example of exceptions introducing faulty behavior unrelated to resource management that I asked for?

  • > example of exceptions introducing faulty behavior unrelated to resource management that I asked for?

    Well there’s a reason that constructors aren’t allowed to throw. Because it would leave objects in a weird hybrid state.

    My physics system example would be the canonical one. You have a system that is transforming from one state to the next. An exception is thrown in the middle of the state transition. Whatever invariants you had for either state is (plausibly) not held. I believe your solution to this was to treat it as a transaction and rewind/restore to the previous state if an error is encountered.

    It’s difficult because I would simply literally never use exceptions for anything ever. My experience with them is strictly negative with zero positives of any kind. I genuinely can not think of a single thing they make better. Nor have I ever encountered a library or codebase where I felt exceptions made it better. But boy howdy have I been frustrated by exceptions.

    boost often has two APIs one with exceptions and one with error code reference arguments. I intend to always use the EC version. And god damn is it fucking frustrating when I accidentally use the exception version and so I get a runtime exception for a vanilla error that I wasn’t expecting. Which is why hidden control flow is evil!

    • >It’s difficult because I would simply literally never use exceptions for anything ever. My experience with them is strictly negative with zero positives of any kind.

      So what I'm getting is that you don't have enough experience with exceptions to judge whether a bug related to exceptions is caused by the code not being exception-safe, thus leaking resources after a throw; by exceptions being thrown for non-exceptional error conditions, thus necessitating excessive try-catching; or by plain old incorrect error handling, thus resulting in trashed program state. So when you encounter a bug like this, instead of figuring out what the actual problem is, you just hack away until there are no more exceptions in sight, and then you actually start to work on fixing the logic. Well, if you're comfortable remaining ignorant and pretending that a language feature doesn't exist, then have at it, I guess.

      >boost often has two APIs one with exceptions and one with error code reference arguments. I intend to always use the EC version.

      I don't like the throwing versions, either, and consider them examples of how not to use exceptions. I'd have to think carefully of a counterexample, but in general I'd say it's a bad idea to throw across library boundaries.

      3 replies →