2
votes

I'm new to dart, and trying to use dart to write a hello world and a unit test, but I get the error:

duplicate top-level declaration 'METHOD main' at ../app.dart::5:6

My project dir is test-dart, and it has 3 files.

test-dart/models.dart

class User {
  hello(String name) {
    print("Hello, ${name}");
  }
}

test-dart/app.dart

#library("app");

#source("./models.dart");

void main() {
  new User().hello("app");
}

test-dart/test/test.dart

#library("test");

#import("../app.dart");

void main() {
  print("hello, test");
}

Now there is an error in "test.dart" on void main(), the error message is:

duplicate top-level declaration 'METHOD main' at ../app.dart::5:6

The two main() methods are in different libraries, why they are still duplicated? How to fix it?

2

2 Answers

6
votes

If you import a library like this #import('../app.dart), then all names from app.dart become visible in the importing code (all public names, actually -- those that don't start with a _). So in your test.dart library, you now have two main functions visible. That is obviously a collision. There are two ways to solve it (that I know of).

First: import the library with a prefix, like this: #import('../app.dart', prefix: 'app'). Then, all public names from app.dart are still visible, but only with an app prefix, so the main function from app.dart is only accessible by app.main. No collision here, but you have to use a prefix everytime.

Second: using a show combinator, like this: #import('../app.dart', show: ['a', 'b']). Then, it is no longer true that all names from app.dart are visible, only those explicitly named (a and b here). I'm not sure if this is already implemented, though.

Maybe in the future, we will get something opposite to the show combinator, so that you could do #import('../app.dart', hide: ['main']). That would be the best solution for your problem, but it isn't in the current language (as specified by 0.09).

5
votes

You are importing app.dart without a prefix which means that the symbols of the importing and imported library can collide if there are duplicates such as in your example.

To resolve these collisions the library import allows you to prefix imports with an identifier. Your example should work if you change test.dart as follows:

#library("test");

#import("../app.dart", prefix: "app");

void main() {
  print("hello, test");
  app.main();
  new app.User().hello("main");
}

Notice how the classes and top-level functions in the app.dart library are now accessed using the "app" prefix and thus do not collide with the names in test.dart.