Live data from Hacker News

Current hardware trends make C++ exceptions harder to justify

open-std.org

451–460 of 516 posts

Re: Current hardware trends make C++ exceptions harder to justify

#451
post #12

This somehow reminded me, wasn't there a competition years back to see who could generate the most compiler error output with the least amount of C++? A few too many templates and you could generate terabytes. Edit: don't think it was this but this is still a fun read https://codegolf.stackexchange.com/questions/1956/generate-t...

I had ten of thousand lines C++ compilation errors that would crash emacs while trying to parse/colorize them.

Still prefer them to the average python error message.

Re: Current hardware trends make C++ exceptions harder to justify

#453
post #438
post #170

Earlier quoted context omitted.

Java's checked exceptions are generally regarded as a mistake. There's a reason no other languages has them, and newer JVM languages (Groovy, Clojure, Scala, Kotlin) treat all exceptions as runtime. Anders Hejlsberg (creator of Delphi, C# and Typescript) also has an excellent article on their problems [1]. In modern Java I see nearly only runtime exceptions used, especially because that's necessary for most Java 8+ l…

> There's a reason no other languages has them, As always someone is wrong on Internet. Java adopted a feature that was initially introduced in CLU, adopted by Mesa/Cedar, Modula-2+ and Modula-3, was being considered for ongoing ISO C++ standardization at the time.

Correct, but also pedantic and doesn't change the point. There's an implied "mainstream" or "currently serious contenders to start new projects in" adjective in "no other languages has them".

Re: Current hardware trends make C++ exceptions harder to justify

#454
post #170

Earlier quoted context omitted.

Java's checked exceptions are generally regarded as a mistake. There's a reason no other languages has them, and newer JVM languages (Groovy, Clojure, Scala, Kotlin) treat all exceptions as runtime. Anders Hejlsberg (creator of Delphi, C# and Typescript) also has an excellent article on their problems [1]. In modern Java I see nearly only runtime exceptions used, especially because that's necessary for most Java 8+ l…

Most of the software I write is designed to be fault-tolerant, and checked exceptions are fantastic way of detecting potential faults. The problem is that checking is baked into the exception definition instead of its usage. If I declare "throws NullPointerException", then this should mean I want it to be a checked exception. This should force the caller to catch the exception, or declare throwing it, or to simply th…

Side stepping that you're using a runtime NullPointerException as an example, Java's checked exceptions are just not particularly good at what you want to do.

If you have a function that has an abnormal result as its API, it should have that as part of its return value, because returning as values is what you do with results. Checked exceptions in contrast don't compose. See for example this code:

   X myFunction(Y param) throws MyFailureException();

   List transformed = list.stream()
     .map(e -> myFunction(e))
     .collect(toList());
This is not allowed, because a the lambda in map can't throw. Even if that was allowed map would need a generic "throws Exception" as its API, which would be awful. With checked exceptions the only possibilities you have is catch the exception locally at the point of calling the function or stop as soon as you encounter the failure and bubble it up.

Instead, if you make the part of the return value you can do whatever. I'll use Vavr Try as an example, but you can also do this in Java 17 with sealed interfaces or in a miriad other ways.

   Try myFunction(Y param);

   List> transformed = list.stream()
     .map(e -> myFunction(e))
     .collect(toList());
Now you can still handle failure locally, but you can also check the whole list and make a decision based on that. Or you can propagate the results including failures because this is not the best place to handle them. That's what I mean with composes vs not composes.

Re: Current hardware trends make C++ exceptions harder to justify

#455
post #417

Earlier quoted context omitted.

The (potential) overhead lies with 'ctx' of course. The lambda syntax makes it all too easy to forget about it.

A pointer argument passed in a register is not what we mean when we say "overhead". Without the lambda, you would instead need to pass the pointer manually, for identically the same cost. But then the compiler would not understand as well what you were doing, and would be unable to optimize it as well. Here, the lambda gives you negative overhead, vs. what you would have written.

You have to look beyond the pointer, of course. (An object and a pointer to it, ‘this’, are two different things.)

Re: Current hardware trends make C++ exceptions harder to justify

#456
post #414

Earlier quoted context omitted.

A lot of C++ developers outside of games don't use exceptions. It introduces a latent and hidden goto up the call chain in your code, and require additional bookkeeping by the program which slows things down. They're also dangerous when you update code because if you introduce a new exception in a function you need to update all of the call-sites. When doing this with monads or sum types, this refactor can be support…

And many more of them do use them. Unfortunely C++ suffers from having people that are so crazy about performance, yet never bother to learn how to use a profiler. That is what boggles my mind, how one can be writing C++ as if they were fitting Assembly into 8 bit home computers, but never bother to learn how to use something like V-Tune. By the way, there are other languages besides Ada with exceptions used for syst…

I do work in software performance. The people I know who don't use exceptions work at HFT firms and in games, but in general, my point is that there's two reasons for not using exceptions:

1. performance

2. not wanting jumps or hidden control flow

Note that with exceptions you're forced to consider C++ exception guarantees for code, which can result in convoluting your code to ensure specific guarantees are met (like using swap to ensure that containers retain previous values), which often gets ignored or implemented incorrectly. Also, with exception specifications being deprecated, you have to rely on documentation or reading code to understand what exceptions might be inherent in other code.

Re: Current hardware trends make C++ exceptions harder to justify

#457
post #441

Earlier quoted context omitted.

I can't imagine error-checking if's being a source of slowness. How are exceptions generated in the first place? Using if's. And anyway, even well structured code is full of if's (e.g. array iteration), and it's not a problem. Especially for error-checking, when the error case is rare, the CPU will correctly predict the branch to take most of the time, so the cost of the if is negligible. The only call where if's sho…

That "if" that guards the throw is the same "if" as would guard the error return. It is the second "if", in the caller, checking the returned result, that up-to-doubles your branch-prediction cache footprint. On, yes, the hot path. Program structure corruption is another problem. They add. Bad code is a tax on all of us.

Which is what I said. And I still don't see how most code that potentially returns errors would be on a hot path. Code that is really on a hot path should probably not call into generic code anyway, and/or that called code should be inlined.

I don't know, as a C programmer, somehow I rarely run into these situations where I have to check error return values. I think the reason is that I work hard to avoid wrappers around wrappers around wrappers. Mostly error checking is required when interacting with the OS - i.e. for I/O, which is not critical paths.

A simple example would be memory allocation. A good C programmer allocates memory upfront. A bad C++ programmer could go, "eh, if it's so convenient I'll simply declare this std::vector locally, and if allocation fails it'll throw an exception and RAII and exceptions will solve the error handling issue magically without me having to type a single keystroke". Of course allocating each time is a lot slower than allocating only a single time upfront; no matter how much faster or convenient and individual allocation and error checking would be. This example shows how the perception of speed can often be warped because we're measuring the wrong thing entirely.

What is bad code is often not clear cut, and neither is how to improve it.

Re: Current hardware trends make C++ exceptions harder to justify

#458

Earlier quoted context omitted.

> one that will never return an error Code that is error-safe is so rare. Why adopt a pattern that elevates the normal case ("here be errors") to information you have to disclose at every turn?

Oh my, this sentiment is common. Errors can't happen inside a Turing machine. The errors are just when you step outside the process to interact with externalities. Computations should be thought of as having errors in it them, any more than the integers do. Network or disk calls maybe have all sorts of things happen. You have to think about the failures whenever you have succumbed to reaching outside of your call sta…

> You have to think about the failures whenever you have succumbed to reaching outside of your call stack for answers.

For any meaningful application, you'll be reaching out of your call stack every fifth line of code.

Re: Current hardware trends make C++ exceptions harder to justify

#459
> The root cause is that the unwinder grabs a global mutex to protect the unwinding tables from concurrent changes from shared libraries.

OK, so replace the mutex with a reader writer lock. Shared library loading is incredibly rare, and dear god I hope nobody seriously does it and expects it to work during unwinding.

Re: Current hardware trends make C++ exceptions harder to justify

#460
post #453
post #438

Earlier quoted context omitted.

> There's a reason no other languages has them, As always someone is wrong on Internet. Java adopted a feature that was initially introduced in CLU, adopted by Mesa/Cedar, Modula-2+ and Modula-3, was being considered for ongoing ISO C++ standardization at the time.

Correct, but also pedantic and doesn't change the point. There's an implied "mainstream" or "currently serious contenders to start new projects in" adjective in "no other languages has them".

Pedantic is good, even C and C++ compilers support it.
Post reply on HN