1

i am learning zig and i have some simple code where i try to declare a method on a struct and try to call that method

here is the code

pub fn main() void {
    const Example = struct {
        a: i8,
        b: i8,
        c: u6 = 5,

        fn prettyPrint(self: *Example) void {
            std.debug.print(" a ---> {}\n b ---> {}\n c ---> {}", .{self.a, self.b, self.c});
        }
    };

    var ex: Example = .{.a = 1, .b =1};
    ex.prettyPrint();
}

but it fails with the following error

zig run ziggity.zig
ziggity.zig:29:31: error: use of undeclared identifier 'Example'
        fn prettyPrint(self: *Example) void {
                              ^

i am on zig version 0.10.0-dev.2024+d127c1d59

what seems to be wrong here?

Palash Nigam
  • 1,653
  • 3
  • 14
  • 26

2 Answers2

4

The issue here is to do with how identifier lookup differs between types of scopes.

The declaration of a variable at container/global scope is distinct from that of one at local scope, in that, in the former case, the identifier that is ultimately bound to is available within its definition, whereas in the latter case, it is not. This can be illustrated in the following example:

const bar = blk: {
    // // compile error for shadowing 'bar'.
    // var bar: u32 = 4;
    // bar += 1;
    // break :blk bar;
    break :blk 5;
};

pub fn main() !void {
    const baz = blk: {
        // fine, because 'baz' is not in scope yet.
        var baz: u32 = 5;
        baz -= 1;
        break :blk baz;
    };
    _ = baz;
}

If you uncomment the first lines, and comment the last line, of the first block, you'll notice the compile errors. From here it should be easy to deduce what your issue is: Example is not available from within its own definition, because it's being declared at local scope. The fix here is to use @This() instead, or alternatively, you could declare const Example = @This(); or const Self = @This(); within Example.

Edit: I should also mention, I'm not actually aware of whether this is intended behavior. I feel that it probably is, but I'm not able to find anything in the langref that states this explicitly, and have simply become familiar with this behavior after encountering it many times.

InKryption
  • 155
  • 1
  • 7
  • Could you spell out for those of use beginners who are stumbling in the dark what you mean by "use `@This()` instead? How would that differ from your alternative which uses `@This()` twice? – hippietrail Jun 20 '22 at 03:35
  • 1
    @hippietrail When I say "use `@This()` instead", what I mean to say is "use `@This()` in place of the name of the type which was declared locally, from within the declaration of said type". So where the OP wrote their `prettyPrint`'s parameter as `self: *Example`, it ought to be `self: *@This()`. Or, alternatively, `self: *Self`, where `Self` has been declared `const Self = @This();` within the type. – InKryption Jul 09 '22 at 23:30
1

this is because main function is executed at runtime and hasn't computed when you define prettyPrint. to fix this, move Example to outside of your main function.

Ali Chraghi
  • 613
  • 6
  • 16
  • 1
    but how is this variable unused? self is clearly used in the print function to access the struct fields, i also don't understand how this has to do with `self` when the compiler points to the struct name calling it undeclared? btw i tried your proposed solutions but they didn't work, the error remains the same – Palash Nigam May 02 '22 at 04:39
  • sorry, i confused your question with something else. answer is edited – Ali Chraghi May 02 '22 at 09:32