Remix.run Logo
jesse__ 7 hours ago

It's remarkable to me how many codebases ban exceptions and yet, somehow, people still insist they're good.

BeetleB 7 hours ago | parent | next [-]

> Our advice against using exceptions is not predicated on philosophical or moral grounds, but practical ones. ... Things would probably be different if we had to do it all over again from scratch.

They are clearly not against them per se. It simply wasn't practical for them to include it into their codebase.

And I think a lot of the cons of exceptions are handled in languages like F#, etc. If f calls g which calls h, and h throws an exception, the compiler will require you to deal with it somehow in g (either handle or explicitly propagate).

jesse__ 7 hours ago | parent | next [-]

My issue with exceptions is also practical. If they didn't introduce significant stability issues, I'd have no problem. As it stands, it's impossible to write robust software that makes use of C++ exceptions.

> the compiler will require you to deal with it somehow in g

I agree, this is the sensible solution.

yunnpp 6 hours ago | parent [-]

What stability issues?

rauli_ 2 hours ago | parent [-]

Unchecked exceptions will eventually lead into programs crashing because some developer forgot to catch specific type of exception somewhere.

jandrewrogers 7 hours ago | parent | prev | next [-]

In low-level systems software, which is a primary use case for C++, exceptions can introduce nasty edge cases that are difficult to detect and reason about. The benefits are too small to justify the costs to reliability, robustness, and maintainability.

Exceptions in high-level languages avoid many of these issues by virtue of being much further away from the metal. It is a mis-feature for a systems language. C++ was originally used for a lot of high-level application code where exceptions might make sense that you would never use C++ for today.

drnick1 6 hours ago | parent | next [-]

> In low-level systems software, which is a primary use case for C++

I don't this this is true. There is A LOT of C++ for GUI applications, video games, all kind of utilities, scientific computing and others. In fact, I find that the transition to "modern" alternatives from native GUI toolkits in C/C++ has led to a regression in UI performance in general. Desktop programs performed better 20 years ago when everything was written in Win32, Qt, GTK and others and people did not rely on bloated Web toolkits for desktop development. Even today you can really feel how much more snappy and robust "old school" programs are relative to Electron and whatnot.

saghm 6 hours ago | parent [-]

To clarify, you think that low-level systems software is only a secondary use case for C++? The part you quoted does not make claims about whether there are other primary use cases, just that low-level systems software is one of them, so it's not clear why it being useful elsewhere is a rebuttal of that.

BeetleB 7 hours ago | parent | prev | next [-]

> In low-level systems software, which is a primary use case for C++

I can assure you: Most C++ SW is not written for low-level.

> exceptions can introduce nasty edge cases that are difficult to detect and reason about.

That's true, except for languages that ensure you can't simply forget that something deep down the stack can throw an exception.

BTW, I'm not saying C++'s exceptions are in any way good. My point is that exceptions are bad in C++, and not necessarily bad in general.

beached_whale 7 hours ago | parent | next [-]

The model of communicating errors with exceptions is really nice. The implementation in C++ ABI's is not done as well as it could be and that results in large sad path perf loss.

jandrewrogers 6 hours ago | parent | prev [-]

> That's true, except for languages that ensure you can't simply forget that something deep down the stack can throw an exception.

Sometimes it is not safe to unwind the stack. The language is not relevant. Not everything that touches your address space is your code or your process.

Exception handlers must have logic and infrastructure to detect these unsafe conditions and then rewrite the control flow to avoid the unsafety. This both adds overhead to the non-exceptional happy path and makes the code flow significantly uglier.

The underlying cause still exists when you don't use exceptions but the code for reasoning about it is highly localized and usually has no overhead because you already have the necessary context to deal with it cleanly.

le-mark 3 hours ago | parent [-]

> Sometimes it is not safe to unwind the stack.

This where garbage collected languages shine.

kllrnohj 6 hours ago | parent | prev | next [-]

If you forget to handle a C++ exception you get a clean crash. If you forget to handle a C error return you get undefined behavior and probably an exploit.

Exceptions are more robust, not less.

nomel 6 hours ago | parent [-]

Yeap. forgetting to propagate or handle an error provided in a return value is very very easy. If you fail to handle an exception, you halt.

vasilvv 2 hours ago | parent [-]

For what it's worth, C++17 added [[nodiscard]] to address this issue.

beached_whale 7 hours ago | parent | prev | next [-]

C++ exceptions are fast for happy path and ABI locked for sad path. They could be much faster than they are currently. Khalil Estell did a few talks/bunch of work on the topic and saw great improvements. https://youtu.be/LorcxyJ9zr4

beached_whale an hour ago | parent [-]

Oops, I meant they are ABI locked so sad path cannot be fixed.

senfiaj 6 hours ago | parent | prev | next [-]

> "In low-level systems software, which is a primary use case for C++, exceptions can introduce nasty edge cases that are difficult to detect and reason about. The benefits are too small to justify the costs to reliability, robustness, and maintainability."

Interestingly, Microsoft C / C++ compiler does support structured exception handling (SEH). It's used even in NT kernel and drivers. I'm not saying it's the same thing as C++ exceptions, since it's designed primarily for handling hardware faults and is simplified, but still shares some core principles (guarded region, stack unwinding, etc). So a limited version of exception handling can work fine even in a thing like an OS kernel.

jandrewrogers 6 hours ago | parent [-]

FWIW, I think it is possible to make exception-like error handling work. A lot of systems code has infrastructure that looks like an exception handling framework if you squint.

There are two main limitations. Currently, the compiler has no idea what can be safely unwound. You could likely annotate objects to provide this information. Second, there is currently no way to tell the compiler what to do with an object in the call stack may not be unwound safely.

A lot of error handling code in C++ systems code essentially provides this but C++ exceptions can't use any of this information so it is applied manually.

matheusmoreira 7 hours ago | parent | prev [-]

Exceptions are actually a form of code compression. Past some break even point they are a net benefit, even in embedded codebases. They're "bad" because the C++ implementation is garbage but it turns out it's possible to hack it into a much better shape:

https://youtu.be/LorcxyJ9zr4

secondcoming 6 hours ago | parent [-]

There is no such thing as the 'C++ implementation' of exceptions. Each vendor can do it differently.

jayd16 7 hours ago | parent | prev | next [-]

Is this correct? I don't know F# but I thought it had unchecked exceptions. How does it handle using C# libs that throw unchecked exceptions?

BeetleB 7 hours ago | parent [-]

My memory of F# is very rusty, but IIRC, there are two types of error handling mechanisms. One of them is to be compatible with C#, and the other is fully checked.

lateforwork 6 hours ago | parent [-]

Unchecked exceptions is a design flaw of C# see here: https://mckoder.medium.com/the-achilles-heel-of-c-why-its-ex...

heyitsdaad 7 hours ago | parent | prev [-]

The “pros” list is exceptionally weak. This was clearly written by someone who doesn’t like exceptions. Can’t blame them.

azov 7 hours ago | parent | prev | next [-]

Most codebases that ban exceptions do it because they parrot Google.

Google’s reasons for banning exceptions are historical, not technical. Sadly, this decision got enshrined in Google C++ Style Guide. The guide is otherwise pretty decent and is used by a lot of projects, but this particular part is IMO a disservice to the larger C++ ecosystem.

alextingle 6 hours ago | parent [-]

I agree. I've worked on large C++ code bases that use exceptions, and they've never caused us any real problems.

ryandrake 6 hours ago | parent | prev | next [-]

I think reasonable people can disagree about whether C++ exceptions are "good" or not.

There are things you can't do easily in C++ without using exceptions, like handling errors that happen in a constructor and handling when `new` cannot alloc memory. Plus, a lot of the standard library relies on exceptions. And of course there's the stylistic argument of clearly separating error-handling from the happy-path logic.

I won't argue that it's popular to ban them, though. And often for good reasons.

canucker2016 4 hours ago | parent [-]

For exception-less C++, you'd declare an operator new() that doesn't throw exceptions and just returns NULL on allocation failure along with a simple constructor and a followup explicitly-called init() method that does the real work which might fail and returns an error value on failure.

tester756 7 hours ago | parent | prev | next [-]

They're good for exceptional situations where foundamental, core assumptions are broken for some reason.

In such scenario there's no error recovery, software is expected to shutdown and raise loud error.

jesse__ 7 hours ago | parent | next [-]

If you're planning on shutting down, what's the fundamental difference between throwing an exception, vs simply complaining loudly and calling exit() ..?

trinix912 7 hours ago | parent | next [-]

Sometimes it’s useful to handle the exception somewhere near its origin so you can close related resources, lockfiles, etc. without needing a VB6 style “On Error GoTo X” global error handler that has to account for all different contexts under which the exceptional situation might have occurred.

PhilipRoman 7 hours ago | parent | next [-]

Your process can crash or be killed at any moment anyway. Depending on in-band cleanup is not reliable.

nomel 6 hours ago | parent [-]

Sure, but there are many cases where you don't have to halt because you can cleanup and carry on.

matheusmoreira 7 hours ago | parent | prev [-]

> a VB6 style “On Error GoTo X” global error handler that has to account for all different contexts under which the exceptional situation might have occurred

... That seems like a pretty accurate description of how exception handling mechanisms are implemented under the hood. :)

einpoklum 6 hours ago | parent | prev [-]

The code that's throwing an exception typically does not know that the exception catcher will shut anything down.

And - very often, you would _not_ shut down. Examples:

* Failure/error in an individual operation or action does not invalidate all others in the set of stuff to be done.

* Failure/error regarding the interaction with one user does not mean the interaction with other users also has to fail.

* Some things can be retried after failing, and may succeed later: I/O; things involving resource use, etc.

* Some actions have more than one way to perform them, with the calling code not being able to know apriori whether all of them are appropriate. So, it tries one of them, if it fails tries another etc.

spacechild1 6 hours ago | parent | prev | next [-]

> They're good for exceptional situations where foundamental, core assumptions are broken for some reason.

No, that's what assertions or contracts are for.

Most exceptions are supposed to be handled. The alternative to exceptions in C++ are error codes and `std::expected::. They are used for errors that are expected to happen (even if they may be exceptional). You just shouldn't use exceptions for control flow. (I'm looking at you, Python :)

ljm 6 hours ago | parent | prev | next [-]

Yet, if you can only explain an exception using the word ‘exception’ you’re not making any head way.

I like the idea of an exception as a way to blow out of the current context in order for something else to catch it and handle in a generic manner. I don’t like the idea of an exception to hide errors or for conditional logic because you have to know what is handling it all. Much easier to handle it there and then, or use a type safe equivalent (like a maybe or either monad) or just blow that shit up as soon as you can’t recover from the unexpected.

dijit 7 hours ago | parent | prev [-]

I use asserts for this purpose.

wvenable 7 hours ago | parent | prev [-]

Looking at this ban list, they've removed everything from C++ that makes it fun. Come on people, who doesn't love a little std::function?!?

On banning exceptions:"Things would probably be different if we had to do it all over again from scratch."

https://google.github.io/styleguide/cppguide.html#Exceptions