Hacker News new | ask | show | jobs
by AnIdiotOnTheNet 2456 days ago
The latter. Zig actually kinda does define this behavior as "`a + b` shall not overflow" and inserts checks in debug and safe builds for it. To get overflow, which zig defines as wrapping overflow, you use a different operator and no check is inserted "`a +% b`". For speed optimized builds, unless you've explicitly told the compiler to insert checks in that scope, it will turn the checks into nops.

So, while it is technically correct to say that it has undefined behavior for overflow, the practical reality is quite different.

1 comments

We do the same thing in Rust, but I think that characterizing this as UB is misleading, personally. We created a new category, "program error", for this, to distinguish from UB proper.

I'm not sure if Zig inherited the defined/implementation defined/undefined hierarchy from C and C++ though.

There's a task to rename UB to illegal behavior: https://github.com/ziglang/zig/issues/2402

As well as some followups to see if Zig can detect all of these errors: * https://github.com/ziglang/zig/issues/1966 * https://github.com/ziglang/zig/issues/2301

Undefined as in undefined by language spec. There are various processor implementations that have different results that are often quite useful. Would you preclude their use?
Right, the key here is that the behavior is defined. That’s why calling it “undefined behavior” is misleading.
It is defined if you want to restrict where your program runs.
If something is defined or not is a property of the language specification, as you stated.

What you’re now bringing up is something different: should a specification define this behavior, or not? I think you’ve properly identified a trade off, but mid-identified the details. Defining a behavior here does privilege certain architectures, but it doesn’t make it impossible. It means the behavior must be replicated in code on some architectures, which is slower.

This is the trade off that Rust (and apparently Zig) are making. This is informed by the architectures that exist, and which ones are wished to support. At this point, two’s compliment is overwhelmingly used, and so the decision was made that defined behavior is worth it. Note the parallel here with POSIX specifying that CHAR_BIT must be set to 8.

Notably, the situation here is so overwhelming that even C++ is specifying two’s compliment: C++20 says that signed integers must be. This was recently voted in. I haven’t read the paper recently and I don’t remember if it changes the UB rule here or not, but it does define the representation of integers, a very similar thing that’s the motivation for UB here.

I was holding out for hardware enforced overflow and underflow checking but I guess it has been abandoned. Thanks for the info. These choices are being made as was made opposite in C standard deliberations... I am interested to see how it will work out.