Friday, February 3, 2012

Code Organization in Dart

‹prev | My Chain | next›

I would like to come up with a decent way to organize my Hipster Dart MVC solution. In Backbone.js, I ended up doing this in one of two ways: namespacing in functions or using require.js to enforce naming. Both approaches had pluses and minuses. Hopefully Dart can do better.

I start by renaming the filenames to start with the MVC type:
$ ls -1
Collection.Comics.dart
Models.ComicBook.dart
Views.AddComic.dart
Views.AddComicForm.dart
Views.ComicsCollection.dart
I found that this approach suited me when working with numerous classes in Backbone. The files are all readily accessible in the same directory, but still grouped based on the MVC type. This also makes it easy to distinguish between Views.Comics and Collections.Comics.

In the files, I do not include the MVC type. Things would just get too noisy if I was extending the ModelComics class with the Hipster Model base class. So I stick with something like:
#library('Model class describing a comic book');

#import('HipsterModel.dart');

class ComicBook extends HipsterModel {
  ComicBook(attributes) : super(attributes);
  get urlRoot() { return "/comics"; }
}
In the class definition, this works fine, but not so much in the main() entry point:
#import('Collection.Comics.dart');
#import('Views.ComicsCollection.dart');
#import('Views.AddComic.dart');

main() {
  var my_comics_collection = new Comics()
    , comics_view = new ComicsCollection(
        el:'#comics-list',
        collection: my_comics_collection
      );

  my_comics_collection.fetch();

  new AddComic(el:'#add-comic');
}
I do not really care for lines like comics_view = new ComicsCollection(). That is a collection view, but it looks more like a collection. I cannot rename the view class to just comics_view = new Comics() because the collection is already named Comics. But, as is, new ComicsCollection() looks like a collection, not the Collection View that it is.

Ew. I suppose that I need to rename all of my classes to prefix them with the MVC type. I cannot find exact documentation in the lanugage spec for what characters are allowed in a class name, but simple experimentation would seem to indicate that it is alphanumeric plus underscore and dollar sign: [A-Za-z0-9_$].

Coming from a Ruby background, I am predisposed to prefer something like comics_view = new View::ComicsCollection(), but the colons are not allowed. The Javascripter in me would not mind a period: comics_view = new View.ComicsCollection(). But again, the period is not legal in a class name. Only underscores and dollar signs are allowed outside of "normal" characters.

Given the choice between:
comics_view = new View$ComicsCollection()
And:
comics_view = new View_ComicsCollection()
I prefer the latter. The dollar sign in the former blends too easily with the rest of the code.

But...

Before going through that tedious exercise, I happen across a reference to Dart's ability to prefix libaries on import. After a bit of digging, I find that this is accomplished with the "prefix" modifier to #import():
#import('Collections.Comics.dart', prefix: 'Collections');
#import('Views.Comics.dart', prefix: 'Views');
#import('Views.AddComic.dart', prefix: 'Views');

main() {

  var my_comics_collection = new Collections.Comics()
    , comics_view = new Views.Comics(
        el:'#comics-list',
        collection: my_comics_collection
      );

  my_comics_collection.fetch();

  new Views.AddComic(el:'#add-comic');
}
Oooh! I like that. That actually solves all of my problems. I can keep my file naming convention, keep the class names small, but have a mechanism to distinguish between the Comics view and the Comics collection.

Yup, that solves all problems. Except it does not work. The second import into the "Views" namespace generates an error:
Internal error: 'http://localhost:3000/scripts/comics.dart': Error: line 5 pos 1: 'Views' is already defined
Nooo!

That has to be a bug, right? I sincerely hope that is a bug because Dart seems to have solved all of my namespacing / naming worries. I will update to latest Dartium and follow up on the mailing list tomorrow. I remain cautiously optimistic in the meantime.


Day #285

2 comments:

  1. Hi Chris,

    This isn't a bug, the prefixes for library import are there to disambiguate the libraries and add a namespace.

    For your use case, I recommend create a library called Views, and #source() each view file into it.

    #library('Views');

    #source('Views.Comics.dart');
    #source('Views.AddComic.dart');

    then over in your main file:

    #import('Views.dart', prefix: 'Views');

    Hope that helps,
    Seth

    ReplyDelete
  2. I stand corrected, Kasper Lund (and the Dart Lang spec) pointed out that prefix names do not need to unique. More here: https://plus.google.com/117928918793969810642/posts/23jbDrM4djW

    ReplyDelete