Thursday, December 6, 2012

Part and Part of Dart

‹prev | My Chain | next›

I am much recovered from yesterday's stomach bug, thank you very much. But today must be another quick offering to the gods of the chain as I have to get my beauty rest for tomorrow's Dart presentation at DevIgnition. It seems only fitting then, that I ought to supplement some of the material from said presentation.

The topic of the talk is ways in which Dart has affected my thinking about programming—both for the web and in general. One of the ways in which Dart has deeply affected my thinking about programming for the web is the absolute necessity for real libraries. I dig require.js and the efforts of many to make ES6 support this, but none of them come close to what Dart does today.

But one thing that I have not played with recently is the #source directive. In fact, it has been so long that there is no longer even such a beast, it has been converted over to part. Let's see if I can figure out how to make it work...

I start with a main.dart file that contains a main() entry point invoking a non-existent function:
main() {
  print(say_hi("Bob"));
}
When I run this script locally, I get the expected failure due to a non-existent function:
➜  code  dart part/main.dart
Unhandled exception:
No such method: 'say_hi', url 'file:///home/chris/repos/dart-presentation/code/part/main.dart' line 4 pos 9
  print(say_hi("Bob"));

#0      NoSuchMethodErrorImplementation._throwNew (dart:core-patch:633:3)
#1      main (file:///home/chris/repos/dart-presentation/code/part/main.dart:4:9)
Next, I define that function in hi.dart as:
say_hi(name) => "Hi, ${name}";
And I add the new part directive to main.dart:
part 'hi.dart';

main() {
  print(say_hi("Bob"));
}
Now when I run that local script again, I get:
➜  code  dart part/main.dart
Hi, Bob
It worked? Oh, I mean yay! It worked.

Actually, I had expected this to fail based on the description in the M1 release notes. Specifically, those notes seem to suggest that, unlike the old #source, the new part needs to be explicit about the library to which it belongs. Based on my quick experiment, it seems not.

Except...

If I run my script through my new best friend in the whole-wide world, dart_analyzer, I find:
➜  code  dart_analyzer part/main.dart 
file:/home/chris/repos/dart-presentation/code/part/hi.dart:-1: Unit is part of library 'null', but has no 'part of' directive (sourced from file:/home/chris/repos/dart-presentation/code/part/main.dart)
    -1: say_hi(name) => "Hi, ${name}";
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compilation failed with 1 problem.
I can fix this warning by declaring a library in main.dart:
library main;

part 'hi.dart';

main() {
  print(say_hi("Bob"));
}
And, in hi.dart, I declare that it is “part” of the main library:
part of main;

say_hi(name) => "Hi, ${name}";
With that, my code passes dart_analyzer and still works properly:
➜  code  dart_analyzer part/main.dart
➜  code  dart part/main.dart         
Hi, Bob
I have to confess that I am somewhat skeptical about this feature. At first blush, it seems like Ruby modules that are factored out of huge classes for the sole purpose of claiming that the code is not, in fact huge. When I do that in Ruby, it is doing no more than hiding the mess in the closet. At least in Ruby there is the pretense that it might be mixed-in elsewhere. In Dart, we are forcing the part to be limited to a single library.

So unless I am missing something, this seems of limited use to me.


Day #591

1 comment:

  1. The 'part' directive is a part of ( :-) ) Dart's library system. The thing you are doing isn't the exact purpose of 'part' (even though it certainly is possible), I'd expect you used 'import' for this.

    Then, there are people who say "one library = one file". Those people never use 'part' and are happy with it. Other people want to split a library to more files, which is when 'part' and 'part of' comes into play. Such multi-file library typically looks like this:

    library my_awesome_lib;

    // all these directives can only be in this file,
    // not in the 'part'-ed files

    // the library usually uses some other libraries
    import ...;
    import ...;

    // and consists of some parts

    part 'part1.dart';
    part 'part2.dart';

    // it is possible to put code here, but unusual

    And the library parts look like this:

    part of my_awesome_lib;

    // lots of high-quality code

    That is the main purpose of 'part' and 'part of'.

    ReplyDelete