Using “prefix” is great for managing how your application references libraries in Dart. At the moment Dart is still in alpha so this exact method or style may change at some later date. From the
Language Specification (0.06) Libraries have a very simple definition.
A library consists of (a possibly empty) set of imports, and a set of top level
declarations. A top level declaration is either a class (7), an interface (8), a type
declaration, a function (6) or a variable declaration (5).
Lets dive in and create one main application and one cipher application that will be a library.
Now if we #import CipherLib from filesystem path into our MainApplication both main functions should conflict.
Why this happens is clearly defined in the specification.
Imports assume a global namespace of libraries (at least per isolate). They also assume the library is in control, rather than the other way around. It is a compile-time error if a name N is introduced into the library scope of a library A, and either: N is declared by A, OR Another import introduces N into the scope of A. This implies that it is a load-time error for a library to import itself, as the names of its members will be duplicated.
The MainAppication can be adjusted by adding the prefix parameter to the #import declaration. Now from the prefixed name we can call the main method.
From this point lets add another library, will call it
XORCipher which will call its library “CipherLib”. The
XORCipher and
CaesarCipher will have libraries named “CipherLib”, both have functions that have the same name but take different parameters. Now we shall run into a problem that could be presented when using others libraries or code, we have conflicting names in the global namespace of our main application.
The way we resolve this is by adding prefix to one or both libraries and call them from the fully qualified names.[sourcecode lang=”java”]
#import(‘../CaesarCipher/CaesarCipher.dart’, prefix:"Caesar");
#import(‘../XORCipher/XORCipher.dart’, prefix:"XOR");
void main() {
String s = "HELLOWORLD";
print("${s}");
s = XOR.EncryptDecrypt(s);
print("After encrypt XOR ${s}");
s = XOR.EncryptDecrypt(s);
print("After decrypt XOR ${s}");
s = Caesar.EncryptDecrypt(s, true);
print("After encrypt Caesar ${s}");
s = Caesar.EncryptDecrypt(s, false);
print("After decrypt Caesar ${s}");
}
[/sourcecode]
Another way to encapsulate source code using libraries is to use the #source declaration in a #library and then to #import the library into your application. From the language specifications:
An include directive specifics a URI where a Dart compilation unit that should be incorporated into the current library may be found. A compilation unit is a sequence of top level declarations. Compiling an include directive of the form #source(s); causes the Dart system to attempt to compile the contents of the URI that is the value of s. The top level declarations at that URI are then compiled by the Dart compiler in the scope of the current library. It is a compile-time error if the contents of the URI are not a valid compilation unit. It is a compile-time error if s is not a compile-time constant.
An example of this type of library can be seen in
HashLib/
hashlib.dart:[sourcecode lang=”java”]
#library(‘hashlib’);
#source(‘hasher.dart’);
#source(‘hasherimpl.dart’);
#source(‘aphash.dart’);
#source(‘bkdrhash.dart’);
#source(‘dekhash.dart’);
#source(‘djbhash.dart’);
#source(‘elfhash.dart’);
#source(‘jshash.dart’);
#source(‘pjwhash.dart’);
#source(‘rshash.dart’);
#source(‘sdbmhash.dart’);
#source(‘nullhash.dart’);
#source(‘bphash.dart’);
#source(‘fnvhash.dart’);
[/sourcecode]
Another great example of this can be seen in
John Evans LUCA UI Framework unit test code. He needed access to some internal dom objects but wanted to preserve the ability to use the elegantly designed
html library. [sourcecode lang=”java”]
#import(‘dart:html’);
#import(‘dart:dom’, prefix:’dom’);
#import(‘../unit_test_framework/UnitTestFramework.dart’);
#import(‘../core/LUCA_UI_Framework.dart’);
[/sourcecode]
Its not uncommon to run into instances where two libraries or source files may define classes, interfaces, functions, type definitions that have similar names in other libraries or source files. The best way to work in these types of situations is to add a prefix where your #import are. A very common one that people run into is with
“html”, Node and Element class. So individuals wanting to create some type of search or sorting might also want to use the Node name, best answer would be to prefix
“html” or your own library code. After your able to reference the library by its fully qualified name, instead of assuming it was globally included. This does feel similar to the
using alias in C#, but with a feeling of inversion of control to the library.
References:
Sample code
dart-using-prefix-example
Language specification