Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
andrewrk opened this issue Jan 18, 2018 · 8 comments
Open
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase. error message This issue points out an error message that is unhelpful and should be improved. frontend Tokenization, parsing, AstGen, Sema, and Liveness.
Milestone

Comments

@andrewrk
Copy link
Member

andrewrk commented Jan 18, 2018

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 andrewrk added the bug Observed behavior contradicts documented or intended behavior label Jan 18, 2018
@andrewrk andrewrk added this to the 0.3.0 milestone Jan 18, 2018
@andrewrk andrewrk modified the milestones: 0.3.0, 0.4.0 Feb 28, 2018
@andrewrk
Copy link
Member Author

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 andrewrk added enhancement Solving this issue will likely involve adding new logic or components to the codebase. and removed bug Observed behavior contradicts documented or intended behavior labels Mar 14, 2019
@andrewrk andrewrk changed the title missing compile error for struct member function shadowing field name add a compile error note for struct member function shadowing field name Mar 14, 2019
@andrewrk andrewrk changed the title add a compile error note for struct member function shadowing field name add a compile error note for field name shadowing struct member function Mar 14, 2019
@andrewrk andrewrk modified the milestones: 0.4.0, 0.5.0 Mar 14, 2019
@daurnimator
Copy link
Contributor

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?
}

@tgschultz
Copy link
Contributor

Related: #1836

@hryx
Copy link
Contributor

hryx commented Mar 30, 2019

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: #1717)

@raulgrell
Copy link
Contributor

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

@ghost
Copy link

ghost commented Jan 24, 2020

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.

@andrewrk andrewrk modified the milestones: 0.6.0, 0.7.0 Feb 10, 2020
@andrewrk andrewrk added the stage1 The process of building from source via WebAssembly and the C backend. label Feb 10, 2020
@andrewrk andrewrk added frontend Tokenization, parsing, AstGen, Sema, and Liveness. and removed stage1 The process of building from source via WebAssembly and the C backend. labels Oct 9, 2020
@andrewrk andrewrk modified the milestones: 0.7.0, 0.8.0 Oct 9, 2020
@andrewrk andrewrk modified the milestones: 0.8.0, 0.9.0 Jun 4, 2021
@andrewrk andrewrk modified the milestones: 0.9.0, 0.10.0 Nov 21, 2021
@Vexu Vexu added the error message This issue points out an error message that is unhelpful and should be improved. label Jul 26, 2022
@andrewrk andrewrk modified the milestones: 0.10.0, 0.11.0 Aug 23, 2022
@andrewrk andrewrk modified the milestones: 0.11.0, 0.12.0 Apr 9, 2023
@Pyrolistical
Copy link
Contributor

Pyrolistical commented Mar 28, 2024

@daurnimator

What about when you take the address of a member?

some_struct.someMethod() is sugar for SomeStruct.someMethod(some_struct).

It is not possible to get a closure like reference to someMethod. someMethod doesn't exist on some_struct as a field, but does exist on SomeStruct as a declaration.

Getting a comptime reference to the someMethod declaration is possible:

const someMethod = SomeStruct.someMethod; // or @field(SomeStruct, "someMethod");
@call(.auto, someMethod, .{some_struct});

@Pyrolistical
Copy link
Contributor

Pyrolistical commented Mar 28, 2024

If we had different syntax for field access and for method calls, this would not be an issue.

One of the reasons why zig so comfy is how light its syntax is. I love the fact the . operator is overloaded:

foo.some_field
foo_ptr.some_field
foo.someMethod()
foo_ptr.someMethod()
foo_ptr.someMethodThatNeedsFooPtr()
Foo.some_declaration
Foo.someMethod
foo_ptr.*
optional_foo.?

I'm so happy I never need to write foo_ptr.*.someMethod() and the fact that ::/-> doesn't exist. In fact, I would go further and replace &foo with foo.&.

I am willing to pay the cost of having to write xxx.bar(&x); as this can be avoided by simply not shadowing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase. error message This issue points out an error message that is unhelpful and should be improved. frontend Tokenization, parsing, AstGen, Sema, and Liveness.
Projects
None yet
Development

No branches or pull requests

7 participants