Search code examples
zig

Method definition on struct fails with "use of undeclared identifier error"


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?


Solution

  • 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.