Search code examples
dartclassglobal-variablesglobalambiguous-grammar

How to distinguish the class member from global variable with the same name in Dart?


I am trying the following code:

String user() {
  return "";
}

class Foo {
  String user;
  Foo() : user = user(); // <= error here
}

void main() {}

But it doesn't work because of name ambuguity.

I can move globals to another module and import as globals to avoid it.

Is there any other way?


Solution

  • The Dart lexical lookup, used to give meaning to plain identifiers, stop at the first scope level which contains a member with that name. Qualified identifiers, the bar in foo.bar, are not looked up lexically, so they do not have the same issue.

    You need to provide a way to access the outer name using either another plain name, or using a qualified name.

    The other plain name is the easier way:

    String user() {
      return "";
    }
    
    String _user() => user(); // Add redirect with other name
    // or `const _user = user;` to create a tear-off.
    
    class Foo {
      String user;
      Foo() : user = _user(); // <= No error now
    }
    void main() {}
    

    Adding a prefix for a top-level name is slightly harder. If it's an imported name, also import the same library with a prefix:

    import "other.dart"; // provides `user`
    import "other.dart" as other; // access also as `other.user`
    ...
      : user = other.user() ...
    

    If the member is declared in the same library, then the solution is the same: Import the library with a prefix. It just feels a little more weird to import the current library into itself, but it's perfectly fine and valid Dart.

    library my_library;
    import "my_library.dart" as self;
    String user() => ...
    // ...
       ...: user = self.user() ...
    

    It's only top-level names that have this issue. Static or instance members can be accessed with a qualified identifier using ClassName.staticMember or this.instanceMember, without needing to introduce a new prefix name.