How to get a mutable pointer of struct literals

const std = @import("std");

const Wrapper = struct {
    i: i32,

    const Self = @This();

    fn add(self: *Self, other: Self) void {
        self.i += other.i;
    }
};

pub fn main() !void {
    var foo = &Wrapper{ .i = 1 };
    var bar = Wrapper{ .i = 2 };

    foo.add(bar);

    std.testing.expectEqual(3, foo.i);
}

The code above will throw error:

~/zig-demo/struct-demo.zig:17:8: error: expected type '*struct-demo.Wrapper', found '*const struct-demo.Wrapper'
    foo.add(bar);
    ~~~^~~~
~/zig-demo/struct-demo.zig:17:8: note: cast discards const qualifier

It seems the pointer of a struct literals is const by default, how to get a mutable one?

1 Like

Why not just this?

    var foo = Wrapper{ .i = 1 };
    var bar = Wrapper{ .i = 2 };

    foo.add(bar);

The compiler is smart enough to essentially rewrite foo.add(...) as Wrapper.add(&foo, ...) for you. If you’re trying to use the mutable pointer to the struct held by foo in another context, just say &foo manually.

This indeed sounds good, but it may conflict with what Zig aimed at No hidden control flow.

If you’re trying to use the mutable pointer to the struct held by foo in another context, just say &foo manually.

I try this (&foo).add(bar) with -fstage1, it works as expected, but failed with stage2

Trace/BPT trap: 5
  • This is my zig version: 0.10.0-dev.4166+cae76d829

The stage2 issue might be a bug, but you don’t need to take its pointer at the call site explicitly.

This is not really control flow, it’s just value passing semantics:

  • when you receive a Wrapper as a function argument, modifications to that object will not be visible outside the function and Zig may pass it by copy
  • when you receive a *Wrapper, modifications to that object will be visible outside the function, and Zig will not copy the value
  • when you receive a *const Wrapper, modifications to that object are not possible, and Zig will not copy the value

Does that make sense? If your local variable foo is mutable and the function call receives a non-const pointer to it, you can use it without any decoration and Zig will do the rest.

2 Likes

Thanks, I just recheck the doc at ziglang, if I want to get a mutable struct pointer, I need to declare struct as mutable first, something like this:

var w = Wrapper{ .i = 1 };
var foo = &w;
var bar = Wrapper{ .i = 2 };

foo.add(bar);

Then Zig compile without errors.

1 Like

Just think of this post when reading release note of 0.10