Friday, December 7, 2012

Parts for Dart Classes

‹prev | My Chain | next›

I may have jumped the gun on criticizing Dart's part operator yesterday. Some of the behavior caught me a bit by surprise, after which it was only natural to jump to the conclusion that its sole use would be for nefarious coding. It's also possible that I might still need to catch up on sleep after a bout with a stomach bug. Ahem.

Anyhow, after some helpful comments in yesterday's post (and some G+ discussion), I think I have a better handle on parts in Dart. I also think I might have an opportunity to use them myself. First, let's make sure that I understand them.

In my main.dart file, I import the Greeter class from a library:
import 'greeter.dart';

main() {
  var standard = new StandardGreeter();
  print(standard.greet("Bob"));
}
I use it to create a standard greeting and print out the result:
➜  code  dart part/main.dart
Hello, Bob
My greeter library is so successful with a single class, I decide to add other kinds of greeters: the "howdy" greeter and the more subdued "hi" greeter. Clearly, it is going to be a maintenance nightmare to define all three classes in one file. This is the point of parts.

The original greeter library with the StandardGreeter class was defined in greeter.dart as:
library greeter;

class StandardGreeter {
  greet(name) => "Hello, ${name}";
}
It's a library. It is a class. The class has a method. Easy-peasy.

Now that I have a bunch of classes, I move them all into their own files: standard_greeter.dart, hi_greeter.dart, and howdy_greeter.dart. The greeter.dart library file now needs to pull in each class, which it does with part:
library greeter;

part 'standard_greeter.dart';
part 'hi_greeter.dart';
part 'howdy_greeter.dart';
Last, but not least, each part has to declare itself the property of this library. These are not reusable code chunks. They belong exclusively to the library. This is where the part of directive comes into play. In standard_greeter.dart:
part of greeter;

class StandardGreeter {
  greet(name) => "Hello, ${name}";
}
In hi_greeter.dart:
part of greeter;

class HiGreeter {
  greet(name) => "Hi, ${name}";
}
In howdy_greeter.dart:
part of greeter;

class HowdyGreeter {
  greet(name) => "Howdy, ${name}";
}
Back in main.dart, the import statement is unchanged—I am still pulling in the greeter library. But now, thanks to the multi-faceted nature of that library, I have access to three greeter classes that can be used to greet Bob:
import 'greeter.dart';

main() {
  var standard = new Greeter();
  var hi = new HiGreeter();
  var howdy = new HowdyGreeter();

  print(standard.greet("Bob"));
  print(hi.greet("Bob"));
  print(howdy.greet("Bob"));
}
No output from the dart_analyzer means that I must be doing something right (or at least not horribly wrong). And, with that, I have my three different greetings:
➜  code  dart_analyzer part/main.dart
➜  code  dart part/main.dart         
Hello, Bob
Hi, Bob
Howdy, Bob
I can very much see the utility of doing something like this. In particular, I can already see that this would help Hipster MVC. In the collection library, for instance, I am currently defining my collection class, event list class, event class, and more in a single file. This was tedious at times. I definitely plan on making use of parts to split those things out into smaller, more manageable files.

It still concerns me a bit that it is possible to extract a bunch of functions into a part as I did last night. A bunch of functions is the opposite of organization. It is the developer equivalent of the junk drawer. But I am happy to avoid the practice, especially if I have yet another way to make the rest of my code stronger.


Day #592

No comments:

Post a Comment