Saturday, December 8, 2012

Dart Library Namespaces

‹prev | My Chain | next›

One of the questions to which I had no answer during my DevIgnition talk was about the uniqueness of library names in Dart. That is, what are the implications of having two different libraries with the same name in the same codebase? I guessed that it would not make a difference, but I dislike not knowing. Sooo....

I create a main.dart that imports two libraries: one for cookies and one for cakes:
import 'cookies.dart';
import 'cakes.dart';

main() {
  var cake = new Cake(3);
  var cookie = new Cookie(12);

  print("""
    cake has ${cake.number_of_layers} layers
    cookie has ${cookie.number_of_chips} chips
  """);
}
Those are two separate libraries, but I use the same dessert identifier for both.

The first library in cakes.dart contains the library dessert directive:
library dessert;

class Cake {
  int number_of_layers;
  Cake(this.number_of_layers);
}
The second library in cookies.dart also contains the library dessert directive:
library dessert;

class Cookie {
  int number_of_chips;
  Cookie(this.number_of_chips);
}
And, as I had guessed, it works just fine. More importantly, it still passes dart_analyzer:
➜  libraries  dart_analyzer main.dart
➜  libraries  dart main.dart         
    cake has 3 layers
    cookie has 12 chips
This was a completely contrived example, but there was always the concern that the same library identifier might be used locally and by a Dart Pub package. It seems that such a case will not be a concern.

While I am mucking about with library namespaces, I might as well play with defining the same name in both libraries. I define a Sprinkles class in cakes.dart that takes a boolean in the constructor:
library dessert;

class Cake { /* ... */ }

class Sprinkles {
  bool chocolate;
  Sprinkles(this.chocolate);
}
And in cookies.dart, I define a Sprinkles class that takes a string in the constructor:
library dessert;

class Cookie { /* ... */ }

class Sprinkles {
  String color;
  Sprinkles(this.color);
}
Lastly, I try to use it in main.dart:
import 'cookies.dart';
import 'cakes.dart';

main() {
  var sprinkles = new Sprinkles(true);
  // ...
}
Now, not only does dart_analyzer dislike me, but the dart compiler hates me as well:
➜  libraries  dart main.dart         
'file:///home/chris/repos/dart-presentation/code/libraries/main.dart': Error: line 5 pos 23: ambiguous reference: 'Sprinkles' is defined in library 'file:///home/chris/repos/dart-presentation/code/libraries/cookies.dart' and also in 'file:///home/chris/repos/dart-presentation/code/libraries/cakes.dart'
  var sprinkles = new Sprinkles(true);
                      ^
Happily, this is why the show and hide keywords exist. I opt to “hide” the Sprinkles definition from the cookies.dart import:
import 'cookies.dart' hide Sprinkles;
import 'cakes.dart';

main() {
  var sprinkles = new Sprinkles(true);

  var cake = new Cake(3);
  var cookie = new Cookie(12);

  print("""
    cake has ${cake.number_of_layers} layers
    cookie has ${cookie.number_of_chips} chips
    the sprinkles are ${sprinkles.chocolate ? 'chocolate' : 'plain'}
  """);
}
Now my code passes dart_anaylyzer and compiles too!
➜  libraries  dart_analyzer main.dart
➜  libraries  dart main.dart         
    cake has 3 layers
    cookie has 12 chips
    the sprinkles are chocolate
I think that about covers my bases on dart libraries. And the next time that I get asked that question about library names, I should be good to go.

Day #593

1 comment:

  1. You can also do this:

    import 'cookies.dart' hide Sprinkles;
    import 'cookies.dart' as xyz; // Alias
    import 'cakes.dart';

    void main(){
    var sprinkles1 = new Sprinkles(true);
    var sprinkles2 = new xyz.Sprinkles("White");
    ...

    }

    ReplyDelete