Sunday, November 22, 2015

Can't Transform My Reflectable Flyweight


Up tonight, I try compiling my Reflectable Dart code into JavaScript. Even if the compiled JavaScript is twice the size of the dart:mirrors equivalent, I would likely stick with Reflectable. The Dart code is just that pretty.

For books like Design Patterns in Dart, I tend to favor built-in libraries to external libraries—even external libraries that are maintained on the core project like Reflectable. I will make an exception for an external package that makes my job of explaining central concepts easier. Reflectable fits that criteria since it converted something like a dozen lines of library and declaration processing into flavor.annotatedClasses (flavor being a custom constant used to annotate my code).

So tonight, I try explore the other promise of Reflectable: better JavaScript compilation. Following along with the project README, I update the pubspec.yaml to include a Reflectable transformer:
name: flyweight_code
dependencies:
  reflectable: any
transformers:
- reflectable:
    entry_points:
      - bin/coffee_orders.dart
    formatted: true
Next, I run pub build to transform this code:
$ pub build --mode=debug bin                   
Loading source assets... 
Loading reflectable transformers... 
Building flyweight_code... (3.0s) 
[Info from Dart2JS]:
Compiling flyweight_code|bin/coffee_orders.dart...
[Info from Dart2JS]:
Took 0:00:01.592568 to compile flyweight_code|bin/coffee_orders.dart.
Built 600 files to "build".
Unfortunately, when I run the code from Dart, I get a bad state error:
$ dart build/bin/coffee_orders.dart                        
here!!!!!!!!!!
Cappuccino
Instance of 'Flavor'
Unhandled exception:
Bad state: Reflectable has not been initialized. Did you forget to add the main file to the reflectable transformer's entry_points in pubspec.yaml?
#0      data (package:reflectable/src/reflectable_transformer_based.dart:119:5)
#1      data (package:reflectable/src/reflectable_transformer_based.dart:118:33)
#2      ReflectableImpl.annotatedClasses (package:reflectable/src/reflectable_transformer_based.dart:1260:50)
#3      CoffeeFlavor.classMirrors (package:flyweight_code/coffee_shop.dart:61:5)
#4      CoffeeFlavor.classMirrors (package:flyweight_code/coffee_shop.dart:60:14)
#5      CoffeeFlavor.CoffeeFlavor (package:flyweight_code/coffee_shop.dart:69:11)
#6      CoffeeShop.order (package:flyweight_code/coffee_shop.dart:24:22)
#7      main (file:///home/chris/repos/design-patterns-in-dart/flyweight/build/bin/coffee_orders.dart:39:7)
#8      _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:261)
#9      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:148)
The first few lines of output there are debug print() statements, but when I hit Reflectable code, it crashes. I am unsure that I understand the error—I clearly put the main() entry file into the pubspec.yaml. Based on the pubspec.yaml for the test_reflectable code, I think I am doing this correctly. But still, I get that error.

I try following the suggestion of the README to use build/bin/packages as the package-root, but I still get the same error:
$ dart -p ./build/bin/packages build/bin/coffee_orders.dart
here!!!!!!!!!!
Cappuccino
Instance of 'Flavor'
Unhandled exception:
Bad state: Reflectable has not been initialized. Did you forget to add the main file to the reflectable transformer's entry_points in pubspec.yaml?
#0      data (package:reflectable/src/reflectable_transformer_based.dart:119:5)
...
Not surprisingly, this also fails if I try to run the JavaScript-compiled version of the code:
$ node build/bin/coffee_orders.dart.js
here!!!!!!!!!!
Cappuccino
Instance of 'Flavor'
/home/chris/repos/design-patterns-in-dart/flyweight/build/bin/coffee_orders.dart.js:671
      throw H.wrapException(ex);
              ^
Bad state: Reflectable has not been initialized. Did you forget to add the main file to the reflectable transformer's entry_points in pubspec.yaml?
    at dart.wrapException (/home/chris/repos/design-patterns-in-dart/flyweight/build/bin/coffee_orders.dart.js:658:17)
...
And, if I compare the transformed version of the bin/coffee_orders.dart file with the original, I find no differences:
$ diff bin/coffee_orders.dart build/bin/coffee_orders.dart
$ echo $?
0
At this point, I have to admit that I am stumped. I try converting this all to a web script with identical results. No matter what I can think to try, I do not seem to get a transformed version of the Dart code that I list in my pubspec.yaml.

This is a bit of a bummer. I still might make use of Reflectable in the book. I assume that I am doing something dumb or there is a minor bug in Reflectable that will get resolved. Likely the former, but if it is the latter, it will surely be resolved long before the book is ready. I may try to identify simpler test cases or try test_reflectable myself tomorrow.

If anyone has any suggestions, my code is at: https://github.com/eee-c/design-patterns-in-dart/tree/master/flyweight.


Day #11


2 comments:

  1. Hi Chris - this is due to an unfortunate compatibility problem with the newest version of the analyzer package.
    We will publish a new version of Reflectable with a restricted version range very soon. Until then you can add a dependency override to the pubspec.yaml:

    ```
    dependency_overrides:
    analyzer: '0.26.1+14'
    ```

    If you see reflectable using unresonably more space than dart:mirrors you are welcome to post bugs at https://github.com/dart-lang/reflectable/issues/new with reproducing code. And we'll see if we can do anything.

    Thanks!

    ReplyDelete
    Replies
    1. Yay! I'm so happy that wasn't me (it almost always is)! If I come across any bugs, I'll be sure to send them your way. I can confirm that the dependency override resolves this particular problem.

      Thanks for such a nice package. Bugs & incompatibilities happen, but they don't change the fact that it's a pleasure working with reflectable :)

      Delete