When to use a struct vs a struct pointer

The old philosophy was to just pass by value by default, only changing the argument to a *const if you have a specific reason, but since the language shifted away from aggressive PRO, it seems that the by-value/by-ref convention is now basically the same as C:

  • Choose a semi-arbitrary amount of bytes (usually 16-64) as the max size of a pass-by-value parameter.
  • When first writing your function, use this byte limit convention. If you need to improve the performance of the function, decide on by-value vs by-ref based on benchmark(s).

If you are referring to const pointers, the pointed-to value can be changed by other pointers.

If you are referring to const values, the value itself can’t be changed by pointers. It would require @constCast to even get a non-const pointer to a const value, and writing to that pointer would be illegal.


This whole by-value vs by-ref thing has always been a slight sticking point for me with Zig, even though it usually isn’t that much of a practical barrier when writing code. I feel like it goes against the philosophy of “one right way to do things”. You could say that “benchmark it” is the ‘one right way’ in this case, but I feel like there still needs to be a widely accepted baseline that is used before optimization/benchmarking, rather than it just being your arbitrary choice of heuristic.

I also don’t think that agreeing on a common byte threshold for by-value/by-ref is a complete solution, as the threshold chosen could become less sensible as hardware changes, plus it would require you to sometimes implement duplicate by-value and by-ref versions of methods for generic structs and structs containing values like usize whose sizes change based on the target.

2 Likes