Hacker News new | ask | show | jobs
by bombcar 41 days ago
I feel we need another category - unspecified behavior. I think everyone would agree the compiler should putout ONE of those answers and that nasal demons would be out of spec.

The problem is that it’s not specified which should be picked, but all pick something.

3 comments

I agree what you say seems reasonable at a glance. But (IIUC) the issue is that for optimization we want the compiler to assume that UB doesn't happen in order to constrain the possible code paths. So if it goes some distance down a possible execution branch and discovers UB it can trim the subtree. At that point "anything can happen" becomes an (approximate) reality.

The obvious counterpoint in this particular instance is that there's no good reason not to make such an awful expression a compile time error.

I also personally think that evaluation order should be strictly defined. I'm unclear if the current arrangement ever offers noticable benefits but it is abundantly clear that it makes the language more difficult to reason about.

As I understand it UB was not really intended to be for optimisation. It was so that C could compile on wildly different architectures that existed at the time.

Today we don't have nearly the variety of architectures, so they in theory C doesn't need nearly as much UB (like more modern languages).

Although there is one modern case where C's "anything goes" attitude has actually helped: CHERI works pretty well with C/C++ even though pointers are double the size they normally are, because doing so many things with pointers is UB (I assume because of segmented memory). CHERI is a slightly awkward target for Rust because Rust makes more assumptions about pointers - specifically that pointers and addresses are the same size.

Which is a form of optimization- if you don’t require something that may be incredibly difficult on a given CPU it makes portability easier.

The reality is these are all edge conditions rarely encountered.

is the fact that CHERI works better with C/C++ because of C/C++'s "anything goes" attitude, or simply that any hardware design that didn't support C/C++ well was discarded?
The C and C++ standards include "Implementation defined behavior", which means that a conforming implementation can do whatever it wants, as long as it specifically documents and sticks to that behavior.

This doesn't really help portability all that much.

That's a different category. Standard defines and uses all 3 "undefined", "implementation defined" and "unspecified" behavior. The difference between last two is that compiler isn't required to document exact behavior. Unlike UB triggering it doesn't automatically summon nasal demons and range of possible behaviors is usually described by standard.
That already exists, and it is in fact called unspecified behavior. Order of function argument evaluation is unspecified, for instance.