Yeah, sorry about the title… I couldn't resist.
I wound up with the strangest little bug in some Polymer.dart code yesterday that I just could not figure out. I had originally started investigating the "is" attribute in Polymer, but quickly realized that I could not use it the way I wanted.
In the end, the best way to implement inheritance in Polymer seems to be with the facilities built into the language. In the case of Dart, that mean regular inheritance with the class
extends
modifier or via mixins. Both work pretty darn well, unless…Unless you are trying to extend one Polymer class with another through a Dart Pub package. Consider last night's code:
import 'package:polymer/polymer.dart'; // import 'a_form_input.dart'; import 'package:a-form-input/a_form_input.dart'; @CustomTag('x-pizza') class XPizza extends AFormInput { // ... }The
a_form_input.dart
files in the local directory and in the package are identical:$ diff -s a_form_input.dart \ ~/repos/a-form-input-dart/lib/a_form_input.dart Files a_form_input.dart and /home/chris/repos/a-form-input-dart/lib/a_form_input.dart are identicalBut when I use the local version, the
attributeChanged()
in from a_form_input.dart
gets invoked:library a_form_input; import 'package:polymer/polymer.dart'; @CustomTag('a-form-input') class AFormInput extends PolymerElement { @PublishedProperty(reflect: true) String name; @PublishedProperty(reflect: true) String value; AFormInput.created(): super.created(); // ... void attributeChanged(String name, String oldValue, String newValue) { print('$name: $oldValue → $newValue'); if (name == 'name') lightInput.name = newValue; if (name == 'value') lightInput.value = newValue; } }When I add toppings to the
<x-pizza>
element, it sets the value
property internally, which triggers the callback (including the print
statement):value: First Half: [] Second Half: [] Whole: [] → First Half: [pepperoni] Second Half: [] Whole: []Making no other change to the
<x-pizza>
element other that importing the package version of a_form_input.dart
results in… nothing. There are no errors, there is no print
statement to be seen in the console and the element is certainly not behaving like "a-form-element", which is the whole point of moving this out into a package.The answer to this little puzzle turns out to be
pubspec.yaml
. If I add a Polymer transformer to the a-form-element package, then everything magically works:name: a-form-input author: "Chris StromBeing somewhat familiar with the idiosyncrasies of Polymer.dart, it did not take long for me to try this. Even so, this fix seems far from obvious. Even now that I know the solution, I cannot rationalize an argument for why this is necessary. I would expect the transformer that is already in my application's" description: "Polymer element that mimics a native <form> input." dependencies: polymer: any transformers: - polymer
pubspec.yaml
would apply to any elements that are imported:name: form_example dependencies: polymer: any a-form-input: path: /home/chris/repos/a-form-input-dart transformers: - polymer: entry_points: - web/index.html - test/index.htmlEven if that did not apply to vanilla elements, surely it would apply to elements that only serve as the base class for an element that is being defined in the application, right? I already know the answer, but the "why" of the no answer remains something of a mystery.
One mystery solved (how to make it work) is enough for today. Tomorrow, I may poke through the transformer again to solve the mystery of why it works.
Day #14
This is a known issue http://dartbug.com/20673. The comments on the issue contain some background information.
ReplyDeleteThe main problems seems to be that transformers can't modify code from other packages.
We stumbled upon this problem when we started working on polymer_ui_elements which imports polymer_elements about a year ago - time just flies by ...
Good to know that I'm not the only one thoroughly confused by that behavior!
Delete