Live data from Hacker News

Current hardware trends make C++ exceptions harder to justify

open-std.org

381–390 of 516 posts

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

#381
post #298

Earlier quoted context omitted.

The distinction some Java programmers make (including myself) is to treat RuntimeExceptions as indicating interface contract violations (usually preconditions), or more generally, bugs. That is, whenever a RuntimeException occurs, it means that either the caller or the callee has a bug. When existing APIs use RuntimeExceptions to indicate any other error condition, they are wrapped/converted into a checked exception…

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.…

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.

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

#382

Earlier quoted context omitted.

When something happens that violates your assumptions about your own program's behavior, throwing it into a state where it doesn't know what happens next. Kind of like a panic.

So, CPU exceptions such as a "page not present" TLB fault should not be used to implement virtual memory.

A "page not present" fault is actually a great example of a resumable condition, which is not quite the same as an exception in the C++ sense.

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

#383
post #296

Earlier quoted context omitted.

Fair. Sounds like you are more claiming that most functions would be better returning a result type, but some will be better with more? I view this as I want my engine to mostly just work. It may need to indicate "check engine" sometimes, though. And that, by necessity, has to be a side channel? I think that is my ultimate dream. I want functions to have a side channel to the user/operator that is not necessarily in…

> I want functions to have a side channel to the user/operator that is not necessarily in the main flow path. That is the essence of the Common Lisp condition system, and you can get there in most languages with closures, or at least function pointers, and exceptions or some other non-local return mechanism using a combination of callback functions for the conditions and unchecked exceptions for the default, unhandle…

I'm not sure callbacks alone can be equivalent to a resumable conditions system. You really need full coroutines in the general case. Anyway, what you are proposing is more of a partial alternative to exceptions, since the caller has to be aware of what's 'handled' in advance, whereas conditions may additionally unwind up to a predefined restart point or fail up to the caller similar to a non-handled exception.

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

#384
One can mix the error abstracts, we have to anyways(cmath methods and NaN). When the distance between the error and the caller that can act on the error is large, it makes much more sense to throw in a large number of cases. Otherwise the cost is code that would have been error neutral becoming error opinionated and that is a software engineering cost.

But look at some of the costs we have to go to great lengths to get around. std::sqrt has to check for invalid inputs and that means a branch, often even when the code is checked prior or an ASSUME( f > 0.0 ) type thing is expressed. This inhibits auto-vectorization. On some compilers ASSUME( not std::isless( f, 0.0 ) ) can tell the compile that the number is real and >= 0 which elides the branch. But the math-error/errno issue is a big hinderance too.

A lot of the costs is the branch itself and telling the compiler it is not needed can boost hot path perf more than the rare cold paths.

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

#385
post #291

Earlier quoted context omitted.

Ada exceptions are fundamentally different from C++ since they only carry type data with a possible message and no other user-defined data. Old school C++ used to have additional try/catch blocks (and performance hit) inserted to ensure that functions match the given exception signature. Also, C++ usually focuses on performance, so all of the bookkeeping required for exceptions could historically be the last 3% or so…

FPS rate should not drive what 99% of other C++ developers are able to use the language for.

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 supported by the compiler as a function signature change.

It boggles my mind that Ada decided to include them. Unless you go through the entire call chain or use SPARK, you don't know for certain that one of the called subprograms won't throw. Even then, you could still get a `Storage_Error` or `Program_Error` for various reasons.

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

#386

Earlier quoted context omitted.

The only way exceptions should be exceptional is that they should rarely be used in any code base. At best, the are a micro optimization that helps you a tiny bit in the success case. They should be used when standard return value errors are measured to be impacting perf (ie. exceedingly rarely). Unfortunately, C++ language authors made them basically a requirement for OOP and RAII. Imagine writing a parser. Can you…

Ok, I'll bite. Disclaimer: I'm not a software engineer, FPGA engineer by training. The use model I have in my mind is that my functions all work 99.999% of the time, but occasionally something happens where basically I want to throw up, I want the whole thing to collapse. Exceptions are great for me. I'm in an industry where "stop" is an okay solution in the rare occasion something goes wrong. So what's the alternati…

> my experience essentially does not involve catching exceptions

Which is part of the problem. If you're not catching the exception, you don't need exceptions. You just need a way to log stuff, such as a trace, and exit the program. New languages such as Rust and Go encourage this explicitly - that is, use the ordained error path in the return value for expected errors, and only panic for catastrophic errors (or use panic in hotpath where return overhead has unacceptable performance impact and errors are super rare).

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p070...

> Programs bugs are not recoverable run-time errors and so should not be reported as exceptions or error codes. — We must express preconditions, but using a tool other than exceptions... migrate std:: away from throwing exceptions for precondition violations.

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

#387

Earlier quoted context omitted.

We've talked about Rust in my monthly beering meetings with other programmers, so it's definitely gaining mindshare to some extend. And it's being prepped for Linux kernel inclusion. Once that lands it will be pretty respectable.

Do many people in the meetings comment about the functional programming feature of rust? That to me is one of the greatest benefits as functional patterns are (at least were) harder in C++ and were definitely less common (which makes code harder for others to understand). In your sample of C++ people, is there much interest in functional programming?

In this group, my friends are all former C programmers, not so much C++. I mean one does what one has to. I think I'm the main Lisp fan, and no Haskell or anything (although I went to high school with a guy that loves Haskell and lazy eval and mathematics of infinite sequences made fully instantiated). I think the idea of pure functions being safe in a way state mutating functions are not is deeply appreciated by C programmers.

In larger groups, I have never found much appreciation for functional programming, and side-effect free APIs/design philosophies to be particularly popular. Usually there's one smart person that loves it, and they make some systems that are 10x as performant as the standard Java whatever and then no one else gets it and it's rewritten into regular OO Java and the person moves on to a more enlightened job.

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

#388
post #361

Earlier quoted context omitted.

We've talked about Rust in my monthly beering meetings with other programmers, so it's definitely gaining mindshare to some extend. And it's being prepped for Linux kernel inclusion. Once that lands it will be pretty respectable.

In other words, talk. Like on HN. Respectable doesn't mean used.

The respectable comment was conditional on it landing in the Linux kernel - I'd be impressed by that. I'm not really aware of any large projects written in Rust, which I find to be a bit of a red flag. There was a project to re-write all the core-utils and such from Gnu in Rust, but I don't think it's gone anywhere. It wouldn't be that much fun because you'd have to replicate all the long options and existing complexity.

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

#389

Wouldn’t changing the global mutex into a read/write be a simple way to fix things? Shared libraries changing the exception table at the same time as exceptions being thrown seems rare. Might also be fixable in an API-preserving way… Edit: nope. This idea is discussed later in the paper (not fully ruled out but the answer may still require ABI changes for more subtle reasons)

Could the mutex be wrapped in a rwlock? New code that don't share state would be able to unwind concurrently while old code would be locked out.

That’s an interesting idea. Might be an elegant way. I was thinking that the exclusive lock could be updated to be RW by hiding the read information in unused bits of the exclusive lock state that’s mutated atomically.

I find the paper’s argument thin on why this could only be done in an ABI incompatible way.

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

#390

Earlier quoted context omitted.

This post is the saddest thing I have ever read in computing. So much power comes about (on the CPU, in the call stack) by being able to assume that things proceed with mathematical tractable properties, as computable functions, plain old general recursion. Distributed things, sure, you have to have protocols and so one to regain the determinism, and even then perfection is no longer achievable, but within your big F…

One errant cosmic particle and all determinism goes out the door as well. The story of computing is not one of mathematics, it's of people and it's of change. Software is about codifying decisions and without perfect knowledge of the universe those decisions are always going to be wrong in some way. And that's even without introducing the infallibility of programmers. Errors are simply part of the process.

ECC and it should be a few cosmic rays :0) but I wouldn't try to write code to work with random bit changes, but implement distributed protocols that can handle a bit of hostility in the data center. Although when the people calling your libraries are bad enough in your call chain, I have found it worth changing the opaque void * from a pointer to a hash value that you look up in an "allocated" structures hash and can return an error rather than dereferencing when they call stuff 5 minutes after calling "de-alloc." (To stop complaints from people calling de-alloc, then calling "do-something" then crashing then blaming my code because I de-ref the opaque pointer.
Post reply on HN