I’m currently exploring how functions can be attached to structs in Zig and I’ve come across something that I find a bit confusing. Here’s a snippet of my code:
const Bar = struct{
pub fn a(self: Bar) void {}
pub fn b(this: *Bar, other: u8) void {}
pub fn c(bar: *const Bar) void {}
};
...
var bar = Bar{};
bar.a() // is equivalent to Bar.a(bar)
bar.b(3) // is equivalent to Bar.b(&bar, 3)
bar.c() // is equivalent to Bar.c(&bar)
In the second and third cases (b and c), it makes sense to me that this and bar are references to the instance of Bar. However, in the first case (a), is self a value or a reference? Is self: Bar just syntactic sugar?
Also, when calling bar.a() or Bar.a(bar), is the bar instance copied? It seems like it would be, but I wanted to confirm if this is the case or if there’s something else going on under the hood.
the compiler passes the instance either by **value or by constant reference**..., but either way you **won’t be able to mutate** the instance
This is very confusing, there is no const, there is nothing telling me that the argument can not be mutated, neither there is anything telling me that it can be reference.
It shouldn’t be confusing that arguments passed by value are immutable. The fact that you pass it by value, e.g. self: Bar, means that you don’t intend to mutate it. And since you won’t mutate it the compiler takes it onto itself to optimize passing the argument however it decides would be best.
There is definitely a little confusion here. One thing to keep in mind that can help clarify is that, in Zig, parameters are always immutable.
With this in mind, it makes a little more sense that a pass-by-value parameter and constant reference parameter can be treated as effectively the same thing. Neither should be mutated, they should just be treated as a copy.
If you want to mutate the underlying data of a parameter, you should pass a normal (non-constant) reference to that data.