there must be better sources to guide people than a poorly written and infantilizing article from 15 years ago.
there must be better sources to guide people than a poorly written and infantilizing article from 15 years ago.
One of the blog posts I've long queued up for writing is "In defense of undefined behavior." It's only half-written, though, but the gist is justifying UB by pointing out that you can't optimize C code with it (via an example using pointer provenance), then pointing out why uninitialized values look weirder than you think by reference to the effects of system libraries, and then I would actually walk through why specification authors should reach for undefined behavior in various places.
One of the things I'd want to say is that UB is a useful and accurate way to model what happens when, say, a program writes over memory used by the allocator. Languages like Odin might try to pretend they don't have UB, but in my opinion it's impossible to get there just by disabling certain compiler optimizations (see https://news.ycombinator.com/item?id=32800814 for an argument about this).
I see UB as essentially a proof obligation, to be discharged in some other way. A really good way is to have UB in the intermediate representation, and compile a safe language into it (with unsafe escape hatches when needed). But there are other ways, including formal methods, rigorous testing, or just being a really smart solo programmer who's learned how to avoid UB and doesn't have to work in a team.
Feel free to send me your draft.
UB is very useful for compiler authors because they can apply very useful optimizations with “illegal” code and then emit illegal code constructs when they want those optimizations to apply. I have a hard time understanding how that’s useful to language users though.
The value of UB is to clearly document what the obligations are for valid programs. It's not valuable to indiscriminately expose that to programmers at scale without some mechanism to discharge those obligations. I don't think C's choices for UB are defensible in a modern world, and for part of that evidence see how many misconceptions there are in this thread (just to pick one, that at least some people think the move to two's complement means that signed overflow is no longer UB). On the other hand, unsafe Rust's choice to include more UB is defensible (aliasing a mutable reference is UB in unsafe Rust but not UB in C) is defensible, as it makes the whole system safer. And Odin's approach (claiming there's no UB when there actually is UB) is even worse from a "clear communication" perspective.
But maybe I should actually write the blog post some time.
One thing I wish unsafe Rust would do, given that there’s more potential for UB in unsafe Rust than in C/C++, would be some way to enforce more compiler checks against UB you didn’t intend to stumble across but I don’t know how that would work or if it’s even possible. But Rust unsafe is decidedly sharper than C++.
The value of UB is to clearly document what the obligations are for valid programs.
I think an argument can be made for C (where annex J exists), but this definitely doesn't apply to C++. Hence the long languishing of P1705.I would also disagree for C though, because annex J can only cover explicit UB by definition and there's the entire category of implicit UB outside that.
As someone that rather prefers Wirth culture on programming languages, UB at the expense of safety isn't a clear win, that is why we end up with security exploits or hardware mitigations for UB based optmizations gone too far.
listen to you, you didn't read the article it's clear, because the article doesn't agree with the rest of what you said. So, since you're not defending an article, you're just attacking me, which is pretty schmucky
There's also no official list for C++, just a proposal to make one that's languished in committee for the past 6ish years.