zig icon indicating copy to clipboard operation
zig copied to clipboard

add a compile error note for field name shadowing struct member function

Open andrewrk opened this issue 7 years ago • 6 comments

const xxx = struct {
    bar: u8,
    pub fn bar(self: *const xxx) void {}
};

pub fn main() !void {
    var x: xxx = undefined;
    x.bar();
}
O:\zig0.1.1\b.zig:10:4: error: type 'u8' not a function
  x.bar();
   ^

andrewrk avatar Jan 18 '18 20:01 andrewrk

I'm going to call this "working as designed". The function is not actually shadowed by the field. It can be referenced like this:

const xxx = struct {
    bar: u8,
    pub fn bar(self: *const xxx) void {}
};

test "non-member fn call" {
    var x: xxx = undefined;
    xxx.bar(&x);
}

However, the error message could be improved with a note that says "note: 'bar' is both a field and a top level declaration". That's a relatively low priority though.

If we had different syntax for field access and for method calls, this would not be an issue. I wonder how well-received it would be for method calls to be a->b().

andrewrk avatar Mar 14 '19 16:03 andrewrk

What about when you take the address of a member?

const xxx = struct {
    bar: u8,
    pub fn bar(self: *const xxx) void {}
};

test "non-member fn call" {
    var x: xxx = undefined;
    var bar = &x.bar; // do I now have a function pointer? or a pointer to the member
    bar(x); // what about now?
}

daurnimator avatar Mar 15 '19 00:03 daurnimator

Related: #1836

tgschultz avatar Mar 15 '19 18:03 tgschultz

I wonder how well-received it would be for method calls to be a->b().

Keeping in mind, if b were a namespaced function and c were a function pointer field, they would require different call syntax:

a->b();
a.c();

But honestly, that might be a good thing if struct "methods" are fundamentally different from struct fields. Which seems to be the case, considering that field values can be changed but namespaced functions can't.

(Possibly affected by this topic: https://github.com/ziglang/zig/issues/1717)

hryx avatar Mar 30 '19 19:03 hryx

I quite like the idea of a separate syntax for method calls since it isn't just "accessing a child of a container", it's also sending an implicit first parameter.

Lua makes this distinction too, where foo:bar() is equivalent to foo.bar(foo).

I'd personally prefer :: instead of ->, both for aesthetic reasons and I believe a new meaning for :: is more easily learned than a new meaning for -> in terms of C/C++.

raulgrell avatar Jan 24 '20 15:01 raulgrell

I'd personally prefer :: instead of ->, both for aesthetic reasons and I believe a new meaning for :: is more easily learned than a new meaning for -> in terms of C/C++.

One possible option is adding a leading comma inside the parenthesis.

a.func(14.3); // normal namespace function
b.func(,14.3); // method. equiv to `TypeOf_b.func(b,14.3)`

// example
const res = a.mul(b.add(c)); // currently
const res = a.mul(,b.add(,c)); //  --  this idea
const res = a->mul(b->add(c)); // traditional

// if spinning further on this idea, but going beyond the concern of this issue: 
// intended to be more explicit and give the reader more information
_ = c.func(,14.3); // method that does _not_ modify `c`
_ = d.func(*,14.3); // method that modifies `d` in place
_ = e.func(&,14.3); // calling a struct member on instance `e`. Run-time dependent behavior.

The leading comma isn't pretty, but it's not very obtrusive (IMO) either. Especially with syntax highlighting.

ghost avatar Jan 24 '20 22:01 ghost