Thursday, October 25, 2012

Dartium isEmpty

‹prev | My Chain | next›

I continue to work through issues in my Hipster MVC based Dart Comics application. The issues stem from recent changes in Dart, most notably those from the recent M1 release.

I believe that I have all of the optional constructor arguments fixed after last night (have I mentioned how awesome those are?). But I still do not have a working application.

I am receiving a nice old stack trace with a less than obvious error message:
Exception: Object is not closure
Stack Trace: #0      HipsterCollection._buildModel (http://localhost:3000/scripts/packages/hipster-mvc/HipsterCollection.dart:75:37)
#1      HipsterCollection.fetch.<anonymous closure>.<anonymous closure> (http://localhost:3000/scripts/packages/hipster-mvc/HipsterCollection.dart:43:33)
#2      List.forEach (dart:coreimpl-patch:355:8)
#3      HipsterCollection.fetch.<anonymous closure> (http://localhost:3000/scripts/packages/hipster-mvc/HipsterCollection.dart:42:21)
#4      _FutureImpl._complete (bootstrap:824:19)
#5      _FutureImpl._complete (bootstrap:832:5)
#6      _FutureImpl._setValue (bootstrap:846:14)
#7      _CompleterImpl.complete (bootstrap:929:26)
#8      HipsterSync._defaultSync.<anonymous closure> (http://localhost:3000/scripts/packages/hipster-mvc/HipsterSync.dart:61:29)
It is reassuring that the Future seems to be completing properly after fetching data from the backend. That exercises a decent amount of code and would appear to be working. As for the error itself, it comes from a seemingly innocuous line inside of Hipster MVC's collection class:
  _buildModel(attrs) {
    var new_model = modelMaker(attrs);
    // Give the factory a chance to define attributes on the model, if it does
    // not, explicitly set them.
    if (new_model.attributes.isEmpty()) new_model.attributes = attrs;
    new_model.collection = this;
    return new_model;
  }
I am unsure if the problem is the condition or the assignment. I try splitting the if statement into a block with the assignment on the following line, which seems to suggest that the error is in the conditional. It is hard to see what I might be doing wrong in there. I try adding a debugger statement:
  _buildModel(attrs) {
    var new_model = modelMaker(attrs);
    // Give the factory a chance to define attributes on the model, if it does
    // not, explicitly set them.
    debugger;
    if (new_model.attributes.isEmpty()) {
      new_model.attributes = attrs;
    }
    new_model.collection = this;
    return new_model;
  }
But is seems that Dartium still does not honor that keyword. It does support explicitly set break points by clicking on the line number in the Dart console:


What I find in there is that isEmpty() is no longer a "regular" method on the attributes HashMap. Now it is a getter. This seems to contradict the "bleeding edge" documentation which still includes the method parenthesis as if this were a normal method:


Has Dart changed so much that getter is somehow implied?

Eventually, I track down a recent mailing list post that explains the situation:
Starting with r14022 isEmpty is a getter now. Affected classes are: Collection, Map, SequenceCollection, String, and StringBuffer.
And indeed, the version of Dartium that I have is after r14022:
➜  hipster-mvc git:(master) ✗ ls -1d ~/local/dartium*
/home/chris/local/dartium-lucid64-inc-11176.11176
/home/chris/local/dartium-lucid64-inc-14060.0
So this is a simple matter of documentation being out of sync with the code. I can't say that I have missed life on the bleeding edge like this. Ah, who am I kidding? I absolutely love this stuff.

After I fix the issue by simply removing the parenthesis:
  _buildModel(attrs) {
    var new_model = modelMaker(attrs);
    // Give the factory a chance to define attributes on the model, if it does
    // not, explicitly set them.
    if (new_model.attributes.isEmpty) new_model.attributes = attrs;
    new_model.collection = this;
    return new_model;
  }
I now have a working Dart application (again):


It has been a couple of months since I last updated my code. In that time, it seems that only two minor things have changed that impact me and, in my estimation, both are for the better. The optional constructor parameters in Dart have always been a big win for the language. To my surprise and delight they are even better in M1. Making isEmpty a getter has a better feel to it. There are never going to be arguments, so why explicitly require the parentheses? Without the parentheses, it is not obvious if this is a property or a method, but it hardly matters. The intent is clear, which trumps anything.

I still need to check editing and deleting records in the Dart Comics app. Assuming those are OK, I will get started publishing the most recent Hipster MVC changes to Dart Pub. Tomorrow.


Day #550

4 comments:

  1. Nice one.
    I guess this will go in the Dart for Hipsters update. Thanks for sharing

    ReplyDelete
    Replies
    1. I suppose that I need to put in the book. My original intention was to get the book updated for M1 as quickly as possible, but it seems that the language designers are not sitting still and I'll have to include even newer changes as well. Darn them and their efficiency! :P

      Delete
  2. correct, and here are the news from Dart:
    http://news.dartlang.org/2012/10/coreimpl-finally-waves-goodbye-and-more.html

    I guess the list would be too long to fetch all methods which have changed to a "getter". But you should be able to automatically refactor your code upon clean up:
    http://news.dartlang.org/2012/10/dart-syntax-changes-landing-soon-update.html

    ReplyDelete
    Replies
    1. Ooh! I had missed that second link, thanks for that one. I think I'll give the auto-refactor a try today. I'm normally a fan of IDEs, but that seems pretty neat :)

      Delete