Of more interest is the import statement, which allows us to import classes for use in our code. From the start, Dart supports this feature that comes standard in all server-side languages. Better still, it works transparently in the browser.
As with the part statement, the source file that is being imported requires the library statement at the top of the file. In both cases, the library statement introduces an isolated scope for the code defined within. Consider, for example, a pretty-printing stopwatch class that might be used to time code.
libraries/pretty_stop_watch.dart | |
| library pretty_stop_watch; |
| |
| class PrettyStopwatch { |
| Stopwatch timer = new Stopwatch(); |
| |
| PrettyStopwatch.running() { |
| timer = new Stopwatch()..start(); |
| } |
| start() { |
| timer.start(); |
| } |
| stop() { |
| timer.stop(); |
| print("Elapsed time: ${timer.elapsedMilliseconds} ms"); |
| } |
| } |
The name in the library statement is used in the output of the dartdoc documentation and in the comments of compiled JavaScript. It also serves as a nice form of documentation.
If we wanted to time how long it took to count to 10 million, we would use our pretty stopwatch like this:
libraries/time_counting.dart | |
| import 'pretty_stop_watch.dart'; |
| |
| main() { |
| var timer = new PrettyStopwatch.running(); |
| for(var i=0; i<10000000; i++) { |
| // just counting |
| } |
| timer.stop(); |
| } |
As nice as the part statement is, the import statement has much more potential for helping to organize our code. Not only is Dart strongly object-oriented, but it makes it dirt easy to share and reuse class libraries, even in the browser.
Recipe 16 | Note: Chrome, or rather Dartium, is smart enough to load part and import files only once, no matter how many different places they might be referenced. |
The import statement allows us to namespace imported classes. Even though we typically import only the classes that we need directly in Dart code, there is still the very real possibility for name collision.
Consider, for example, the case in which our MVC application needs the Comics collection as well as the Comics view. Both would be declared as class Comics (although they would extend HipsterCollection and HipsterView). If we attempt to import them directly, Dart’s compiler throws an already-defined exception.
To get around this potential limitation, we prefix the imports.
libraries/prefixed_imports.dart | |
| library prefixed_imports; |
| |
| import 'collections/Comics.dart' as Collections; |
| import 'views/Comics.dart' as Views; |
| import 'views/AddComic.dart' as Views; |
With that, we no longer reference the Comics view class or the Comics collection class. Instead, we use Views.Comics and Collections.Comics.
| main() { |
| var my_comics_collection = new Collections.Comics(), |
| comics_view = new Views.Comics( |
| el:document.query('#comics-list'), |
| collection: my_comics_collection |
| ); |
| } |
The implication of prefixes is that there is no global object namespace in Dart. The main entry point has its own isolated workspace, with its own classes and objects. The various libraries that are imported all have their own object namespace. This cuts down on much of the ceremony involved with code organizing and is another way that Dart encourages us to write clean code.
3.141.3.175