Access outer scope(s) of an anonymous struct

consider this fragement:

pub const x = 100;
pub const y = 101;

pub fn G() type {
    return struct {
        pub const y = 201;
        pub fn f() void {
            _ = x // `x` found in the outer scope
            _ = @This().y;  // `y` from inner scope
            // how do i access `y` from the outer scope ???
        }
    };
}

how do i access y (= 101) defined in the outer scope from within member function f() ???

my actual use-case calls a comptime function within the anonymous inner struct, which then tries to locate some decl y found in some lexical scope starting with @This()…

said another way, can i obtain a “slice” of nested scopes which i could then query with @hasDecl() ???

For accessing a variable, within a file, you can define your outer scope:

// top of foo.zig
const outer = @This();

I find this is helpful if I have member functions that call file-level functions that have the same name:

pub fn foo(...) void {
    outer.foo(...);
}

how do i access y (= 101) defined in the outer scope from within member function f()???

Zig only allows shadowing when the shadowed variable can be accessed by a namespace lookup, i.e. it is a container-level declaration (meaning, within a struct/union/enum/opaque declaration). Since files are implicitly structs (if you didn’t know this: files are structs! You can put fields at top-level if you’d like!), this applies to top-level declarations. So, you need to do a namespace lookup on that struct, which, as indicated by the above commenter, you can use @This() for.

can i obtain a “slice” of nested scopes which i could then query with @hasDecl()???

No, there’s no way to programmatically get a list of scopes like that.

In general, I’d encourage avoiding shadowing even in this case where Zig permits it: it’s rarely a good idea. Not never, but rarely.

this is obviously a contrived example… but is there a way to programmatically access x (not being shadowed) given the container @This() referring to the inner scope???

No, there isn’t a programmatic way to go from a container type to its “parent” (in the sense of “syntactically enclosing”) container type, which would be necessary to access its x.

EDIT: wait, did you mean accessing the inner x (the one within f)? Either way, the answer is still no: x is declared within a function, which means you can’t access it through a namespace lookup whatsoever! It can only be referenced directly by name, and so shadowing it in any way would be a compile error. The @This() within f isn’t referring to f itself or some scope within it: it’s just the struct we’re within. @Type() returns the innermost syntactically enclosing container type.

so @field(@This(), "x") doesn’t work??? given that the compile CAN find x, shouldn’t there be a “scope searching” variant of @field ???

using the suggestions that @AndrewCodeDev gave, i could certainly find a solution that works in my specific scenario…

there is only one x – defined in the outermost scope… there is no problem referring to this declaration as simply x within the method f of my inner struct…

Ah, yep, sorry, misread the code! You’re correct that @field(@This(), "x") won’t work from within f (or anywhere in the struct).

given that the compile CAN find x, shouldn’t there be a “scope searching” variant of @field?

Namespaces and scopes are somewhat distinct concepts in Zig. Scope lookups consider local variables, and do not consider usingnamespace; namespace lookups do the opposite. As a similar restriction, scope lookups consider syntactic parents, whereas namespace lookups do not. There’s not really much reason to change this: it would just complicate the language.

It’s worth remembering that these lookups are exactly what you’re doing when you write code like std.foo.bar; taking the struct type std (which happens to have no fields, so we’re using it solely as a namespace), accessing its foo declaration, and accessing that struct’s bar declaration. Expanding these lookups to consider syntactic parents would have some very strange implications regarding namespacing.

4 Likes