I don’t think there is, because that is antithetical to what Zig is working towards. Consider parameter reference optimization (PRO), for instance. Zig is trying at all levels to take the decision of when to make a copy away from the programmer. This should lead to more ergonomics to the programmer, who doesn’t have to worry about this, and better performance, as the compiler can really micromanage every byte. Overall, this works great, but examples like this show that it can fail in very subtle ways. In a large code base, this bug would be nearly impossible to catch. Specially worrying is how fickle it is, a simple _ = &b
, that was made some lines away, was all it took to make the bug disappear (temporarily, as any change to the code around this could make it reappear).
In the identity function that you showed, the compiler could inline it and perform all the same optimizations. Even if you forbid it from inlining, given that Zig is agressively working towards eliminating extra copies, it could still deduce that the value returned will be the same the as the argument, and make code transformations based on this. If you think about it, the line const b = a
is equivalent to the identity function you showed, with a
being the input and b
the return value. Here b
is a value that, from a logical standpoint, is a copy of a
. The compiler could implement this as a reference, but it would have to ensure that the illusion of it being a copy was never broken. The fact we can see what’s happening behind the curtains is a compiler bug. If the compiler broke the line const b = a
, it will break anything that achieves the same result, even the identity function.
They are well aware of these issues. What we’re seeing here is just a variation of the aliasing issue. See this post from Andrew. In the post, and in various other media, Andrew has argued that this problem is not as big as it seems, which is why it hasn’t been properly dealt with, but I disagree.
Matklad has already commented that in TigerBeetle they stopped using value arguments altogether to avoid aliasing issues, passing pointers everywhere, which is the opposite of what PRO was trying to achieve. They are going out of their way to purposefully give up all of value semantics, therefore giving up all of the performance and ergonomic benefits that PRO was supposed to bring. They would get better performance and ergonomics by explicitly deciding when to make a copy, like in C.
Anyone programming in Zig is (or should be) always afraid that a bug like shown in the example will suddenly appear in our codebase. One small change in the compiler, or one simple line in your own code, could make the aliasing issue appear and create a massive Heisenbug. Nobody would be crazy to bet a really large project on a language where you can’t have the most basic faith that your arguments will be passed correctly, specially if the code may work today and break tomorrow based on the compiler’s humor that day. When you can’t have faith in such a basic aspect of the language, it shatters the faith in the language itself.
To me, the aliasing issue is the most important issue currently in Zig, to the point that it may break the entire language. Specially given that we don’t know if it’s even solvable. If it can’t be solved, we’re gonna have to make some drastic changes, like impose limits on certain things like global variables or even go back to the C way of passing arguments. Whether this is solvable or not will completely shape the language, which is why it should be tackled on as early as possible.