# Integer addition is not associative, or should we put constants to the right?

**URL:** <https://ziggit.dev/t/integer-addition-is-not-associative-or-should-we-put-constants-to-the-right/18254>\
**Category:** Explain\
**Tags:** language\
**Created:** [November 6, 2026, 12:34pm UTC](https://ziggit.dev/t/integer-addition-is-not-associative-or-should-we-put-constants-to-the-right/18254 "2026-11-06T12:34:54Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Olvilock](https://ziggit.dev/user_avatar/ziggit.dev/olvilock/32/4074_2.png) [@Olvilock](https://ziggit.dev/u/Olvilock)\
**Post date:** [November 6, 2026, 12:34pm UTC](https://ziggit.dev/t/integer-addition-is-not-associative-or-should-we-put-constants-to-the-right/18254/1 "2026-11-06T12:34:54Z")

</div>

An example in the release notes on [Operator Precedence](https://ziglang.org/devlog/2026/#2026-10-24) with a lot of parentheses inspired me to check whether I know all the side effects of the defined order of operations.

One of the quirks of the integer overflow UB I had not realized before is that, since it is observed by the compiler operation-wise, this UB (and the transformations the compiler does because of it) is sensitive to the order in which arithmetic is performed. In particular, I would argue that, in the status quo, omitting parentheses in a chain of additions has implicit control flow.

Take a look at this [example](https://godbolt.org/z/Wbzr7rxer), keeping in mind that addition is left-associative. In the compare\_good function, both a + b and c + d are evaluated first, so the compiler sees the guarantee that they fit into i32. In compare\_bad, a - 10 and c - 10 are evaluated first, so there is no such guarantee, and removing -10 might cause an extra overflow on either side of the less operator. Even the explicit evaluation (and assertion) in compare\_ugly cannot resurrect the optimization since dead code elimination stole this information way earlier.

Unfortunately, the compilers relying on SSO have to do operation-wise UB, and not make just the results of the whole associative operation UB on overflow. Nonetheless, the optimizations would be more consistent if only the final result were checked (or assumed). For now, we might want to just put our constants at the very right in arithmetic for better optimizations sometimes.

What do you think about this?

---

<div class="post-metadata">

**Author:** ![alanza](https://ziggit.dev/user_avatar/ziggit.dev/alanza/32/6006_2.png) [@alanza](https://ziggit.dev/u/alanza)\
**Post date:** [November 6, 2026, 1:18pm UTC](https://ziggit.dev/t/integer-addition-is-not-associative-or-should-we-put-constants-to-the-right/18254/2 "2026-11-06T13:18:40Z")

</div>

Firstly, Zig does not have a concept of “UB” in the way that C and C++ do. Zig has “illegal behavior”.

Secondly, you’ve misinterpreted what the Godbolt output is telling you. What you are actually seeing is that in the “compare\_good” function, the compiler is able to see the optimization that `x < y` and `x - 10 < y - 10` are the same comparison, if it ignores overflow, while it misses that optimization in the `compare_bad` function. Please note that “missing an optimization” is very different from the claim “integer addition is not associative”.

Of course, you are right to call out that the comparison `x - 10 < y - 10` has an edge case where the computation underflows. The compiler is empowered to ignore this edge case because 1) you wrote `+` and `-` and not one of Zig’s other operators like `+|` or `+%`, and 2) you compiled in `-Ofast`, which turns underflow/overflow checks into assumptions that the compiler may use to optimize.

---

<div class="post-metadata">

**Author:** ![vincentd](https://ziggit.dev/user_avatar/ziggit.dev/vincentd/32/9870_2.png) [@vincentd](https://ziggit.dev/u/vincentd)\
**Post date:** [November 6, 2026, 2:21pm UTC](https://ziggit.dev/t/integer-addition-is-not-associative-or-should-we-put-constants-to-the-right/18254/3 "2026-11-06T14:21:25Z")

</div>

I’m not fond of having having more than 2-3 variables in a line.

[Much better](https://godbolt.org/z/eG4MTfbs7)

Now that the red mist has cleared…

Can’t say I’m too surprised. Optimising compilers are a bit of a dark art, best not rely on them too much. Thankfully it’s only a few instructions, so you’re not losing too much. If my program is running slowly, there are much better places to start than trying to enable micro-optimisations at this level.

I guess it could elide a function call in some circumstances, assuming the function (1) computed a value and (2) had no side effects. I’d be hard pressed to think of an example, though. One that wasn’t just bad code in some other way.

* * *

While I was rewriting the code in godbolt, I found some instances of the same code compiling into different instructions when I changed the name of the function, or it’s position in the file.

> **Example**
>
> [This](https://godbolt.org/z/KTeKshbxh) compiles into
> 
> ```zig
> lea eax, [rdi + rsi - 10]
> lea ecx, [rdx + rcx - 10]
> cmp eax, ecx
> setl al
> ret
> 
> ```
> 
> but [this](https://godbolt.org/z/KEnfGsPns) compiles into
> 
> ```zig
> lea eax, [rdi + rsi]
> add eax, -10
> add ecx, edx
> add ecx, -10
> cmp eax, ecx
> setl al
> ret
> 
> ```

Maybe it’s able to optimise more when compiling alongside other, similar functions… and then it keeps the result in the cache… I can only speculate.

* * *

> [@alanza](#):
>
> Firstly, Zig does not have a concept of “UB” in the way that C and C++ do. Zig has “illegal behavior”.

“Unchecked Illegal Behaviour” has identical semantics to C’s “the behavior is undefined”.

Different name, same pit of angry venomous snakes.

---

<div class="post-metadata">

**Author:** ![pzittlau](https://ziggit.dev/letter_avatar_proxy/v4/letter/p/ecae2f/32.png) [@pzittlau](https://ziggit.dev/u/pzittlau)\
**Post date:** [November 6, 2026, 4:01pm UTC](https://ziggit.dev/t/integer-addition-is-not-associative-or-should-we-put-constants-to-the-right/18254/4 "2026-11-06T16:01:19Z")

</div>

> [@vincentd](#):
>
> “Unchecked Illegal Behaviour” has identical semantics to C’s “the behavior is undefined”.
> 
> Different name, same pit of angry venomous snakes.

That is true but note that the list of unchecked illegal behaviour is much smaller than the one of undefined behavior. At least for safe release modes.

AFAIK it’s just `@fieldParentPtr`, return of pointer to the call frame and wrong assembly clobbers.

That is much better than other languages. And I think one _could_ find a way to make them safety checked swell.

---

<div class="post-metadata">

**Author:** ![vincentd](https://ziggit.dev/user_avatar/ziggit.dev/vincentd/32/9870_2.png) [@vincentd](https://ziggit.dev/u/vincentd)\
**Post date:** [November 6, 2026, 4:27pm UTC](https://ziggit.dev/t/integer-addition-is-not-associative-or-should-we-put-constants-to-the-right/18254/5 "2026-11-06T16:27:23Z")

</div>

Agreed, it is much better, especially in `debug` or `safe` mode.

My point is more around wording; Zig has ‘undefined behaviour’ in all but name, and saying it doesn’t will only confuse people.

There is also the existing literature on the topic of undefined behaviour, and the [weird](https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633/) and [wacky](https://markshroyer.com/2012/06/c-both-true-and-false/) behaviour it can cause. It can help encourage people to stay in `safe` modes.

---

<div class="post-metadata">

**Author:** ![alanza](https://ziggit.dev/user_avatar/ziggit.dev/alanza/32/6006_2.png) [@alanza](https://ziggit.dev/u/alanza)\
**Post date:** [November 6, 2026, 4:34pm UTC](https://ziggit.dev/t/integer-addition-is-not-associative-or-should-we-put-constants-to-the-right/18254/6 "2026-11-06T16:34:13Z")

</div>

ah, i guess i should have been more explicit: I called it out bc the mention of “UB” and odd conclusions made by the post had me suspecting we caught the tail end of an LLM folie à deux, but i didn’t say as much 🙂
