Hacker News new | ask | show | jobs
by jforberg 2610 days ago
The section about overflow put me off. Undefined semantics is one of my least favourite parts of C. It seems from the article that Zig is leaving not only signed overflow but also unsigned overflow as undefined (or runtime crash in "safe" mode, which is equally as bad). In C at least unsigned arithmetic is well-defined so I could get away with some casting back and forth.

This irks me especially badly since the underlying hardware operations are almost always well-defined, but in my "high-level" language I constantly have to worry that I missed something and maybe the compiler will "optimise" my + into something other than addition.

Is there a fully well-defined addition operator in Zig? What about a well-defined shift operator? This might make me, as a professional C programmer, more interested in a new C-like language.

2 comments

I think we just need a terminology update: https://github.com/ziglang/zig/issues/2402

Would you feel better if it was called "illegal behavior"? In the safe build modes of Zig, integer arithmetic, shifting, wrong union field access, etc is 100% well-defined. Integer overflow is defined to panic. Unless of course you use one of the wrapping arithmetic operators; in these cases it is defined to do wrapping arithmetic.

Integer overflow is usually a bug. If it weren't illegal behavior, zig wouldn't be able to help you catch the bug. That's why clang's integer arithmetic sanitizer only works for signed ints. It's much better for programmers to specify their intent precisely, which is why Zig has different operators for wraparound and assert-it-doesnt-overflow.

Undefined behavior in the unsafe modes is what lets the optimizer make code go fast. C has given undefined behavior a bad reputation, but it's a tool. Zig lets you decide exactly where to opt in or out of the speed/safety tradeoffs.

That sounds reasonable. I agree that overflow is often a bug (and in GCC can use -ftrapv to enforce that view). But overflow is also frequently what you want in algorithms that deal with counters or differences of sums. Maybe point out that there are well-defined operators available in Zig as well?

I'm not immediately seeing how non-wrapping arithmetic can enable significant optimisation. What could be faster than an integer add? If you have an example, I would be very interested (the classic "infinite loop" example is not particularly meaningful in my view).

I always assumed that C left this undefined mostly to support non-two's complement machines, which should probably not be a concern anymore. That's the only explanation I can come up with that explains why unsigned arithmetic is well-defined, but not signed arithmetic.

Illegal behavior is a better name for a code sequence that is guaranteed to panic. There is too muchalready-established meaning around C and C++'s use of the phrase "undefined behavior"
You can use +% to have a fully defined wraparound addition: https://ziglang.org/documentation/master/#Wrapping-Operation.... For lshift, there is @shlWithOverflow.
Nice! That's something I often wish GCC had.
I google'd this - GCC comes close. There are built-ins for overflow-checking add/sub/mul arithmetic. [0] There are also compiler flags to enable explode-on-overflow or wrap-on-overflow, except for division and remainder. [1]

[0] https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins...

[1] https://www.gnu.org/software/autoconf/manual/autoconf-2.63/h...

Indeed. What I would really like is a way to toggle it on case-by-case basis. With -fwrapv you have to convince the code owner to toggle it globally, which can complicate things unless you are the owner.
Looks like GCC doesn't have a pragma to enable it on a per-object-file basis. Pity. From the pragma docs I get the impression it's not so much that it would be a bad idea, as simply not something they've got round to implementing.

I don't imagine it's possible to check using a static assert, either.

https://gcc.gnu.org/onlinedocs/gcc/Pragmas.html#Pragmas