Does Zig guarantee left-to-right order of evaluation? For example, in an expression like f() + g() or a statement like f().* = g(); will f() be called before g()? This is guaranteed in many languages, but notably not in C or C++.
Based on Zig’s design principles, I would guess that Zig does guarantee this, but I couldn’t find an explicit statement along those lines in the language spec.
I tested a few examples and it seems to always execute them left-to-right.
I could not find any reference of this behavior in the documentation.
However, given that zig needs to be compatible to C in some degree (code can be translated from C to zig in some capacity to import headers into zig) I would guess that this behavior will stay.
But is it really a good idea to rely on details like this? Most people probably won’t know about it, so your code might be confusing to them. In my opinion it is better to explicitly state the order, if you rely on it:
const ptr = f();
ptr.* = g();
And the best option of course would be to avoid these side-effects if possible, or make them more explicit.
As briefly mentioned by OP, this behavior is not guaranteed in C. Regarding evaluation order, the C standard, roughly speaking, states that side effects will never be reordered past a “sequence point” (*). For instance, C’s comma operator , is defined as a sequence point, so a,b is guaranteed to perform any side effects of a before evaluating b. Similarly, the end of a statement (i.e. a semicolon) is a sequence point. Most standard operators, like + and =, are not sequence points in C, so the compiler is free to reorder the side effects of sub-expressions as it wishes.
Nowadays, this restriction seems rather less necessary: compilers are generally smart enough to figure out when they can reorder side effects, elide loads, etc if it would help with optimization. As such, whilst I do not know if it has been formally defined at any point, I do expect Zig to ultimately include the status quo behavior in its spec, where sequencing of side effects always happens in the order of the source code (which I can confirm is guaranteed in the current compiler implementation, and in fact would be quite difficult for us to change due to how the compiler pipeline is structured).
*: It’s technically defined differently since C11, but the new definition is basically equivalent.