Duplicate var names

We cannot have local var names inside a struct function that are equal to a field in that struct.
Mostly that is strange because we always have to access that field with self.xxx.

So is that restriction only because of the phenomenon “files are structs”?
(In that case we have no thisfile.xxx)

The absence of identifier shadowing in Zig seems to be more a decision to improve readability than anything else. Zig guarantees that an identifier, once declared in a scope, always refers to the same object in that scope and all of its descendant scopes. Moreover, it’s been decided that declarations and fields share the same namespace, to allow for decl literals (the thing where you can call .init() and it infers the namespace from the result type).

I don’t think there is anything technically preventing Zig from supporting shadowing of identifiers. It was a purposeful decision to not allow it.

You can still totally use @This().xxx

1 Like

Actually we can. What is not possible is having local variables with the same name as global variables namespaced in the struct, because these are accessed without self.xxx.

const S = struct {
    field: i32,
    var global: i32 = 3;

    pub fn func(self: *S) void {
        self.field = 5; // accesses the struct field
        var field: i32 = 42; // no problem
        global = 13; // accesses the global variable
        var global = 12; // ERROR
    }
};
2 Likes

Ow damn… you are right.
Edit: Aha…
We cannot use the name of a function. THAT was the thing i encountered.
And that is logical.

See, this is where the argument breaks down for me. Every single time I try to shadow, it’s intentional. In fact, it usually prevents future errors, because it narrows down the scope of things. And I’m too old and stupid to deal with wide scopes of things.

In languages that allow shadowing I try to to use it to immediately eliminate a no-longer-necessary variable from the namespace:

const path = "file path";
const aw_wtf = std.path.windowsParsePath(path);

// oh gosh, I sure like having `path` still available in my namespace

std.fs.whatever(pa^H^Haw_wtf);

See also:

if (thingie) |cant_call_this_thingie| {
    // but sure wish I could
}
3 Likes

yes. very annoying but logical. I always am short of useful names in that case.

1 Like

FWIW, you can use block expressions for that (in most cases):

const aw_wtf = blk: {
	const path = "file path";
	break :blk std.path.windowsParsePath(path);
};

// `path` doesn't exist, it can't hurt me :-)

std.fs.whatever(aw_wtf);

… except for this, yes:

But at that point, I usually rename thingie to thingie_opt, then capture it as thingie:

if (thingie_opt) |thingie| {
    // happy, happy, happy :-)
}

Yep, same. But at that point we’re in Hungarian notation territory, and no offense to Magyar people, but surely we can do better!

1 Like