| Index: pkg/polymer/lib/src/instance.dart | 
| diff --git a/pkg/polymer/lib/src/instance.dart b/pkg/polymer/lib/src/instance.dart | 
| index 3cc2e1a55a02a3e86afe83ccbbd454869e04f94f..b63ef93e49428d28ba012fa92d514d7d0a8ce9ea 100644 | 
| --- a/pkg/polymer/lib/src/instance.dart | 
| +++ b/pkg/polymer/lib/src/instance.dart | 
| @@ -4,7 +4,7 @@ | 
|  | 
| part of polymer; | 
|  | 
| -/// Use this annotation to publish a field as an attribute. | 
| +/// Use this annotation to publish a property as an attribute. | 
| /// | 
| /// You can also use [PublishedProperty] to provide additional information, | 
| /// such as automatically syncing the property back to the attribute. | 
| @@ -24,15 +24,31 @@ part of polymer; | 
| ///       // | 
| ///       // If the template is instantiated or given a model, `x` will be | 
| ///       // used for this field and updated whenever `volume` changes. | 
| -///       @published double volume; | 
| +///       @published | 
| +///       double get volume => readValue(#volume); | 
| +///       set volume(double newValue) => writeValue(#volume, newValue); | 
| /// | 
| ///       // This will be available as an HTML attribute, like above, but it | 
| ///       // will also serialize values set to the property to the attribute. | 
| ///       // In other words, attributes['volume2'] will contain a serialized | 
| ///       // version of this field. | 
| -///       @PublishedProperty(reflect: true) double volume2; | 
| +///       @PublishedProperty(reflect: true) | 
| +///       double get volume2 => readValue(#volume2); | 
| +///       set volume2(double newValue) => writeValue(#volume2, newValue); | 
| ///     } | 
| /// | 
| +/// **Important note**: the pattern using `readValue` and `writeValue` | 
| +/// guarantees that reading the property will give you the latest value at any | 
| +/// given time, even if change notifications have not been propagated. | 
| +/// | 
| +/// We still support using @published on a field, but this will not | 
| +/// provide the same guarantees, so this is discouraged. For example: | 
| +/// | 
| +///       // Avoid this if possible. This will be available as an HTML | 
| +///       // attribute too, but you might need to delay reading volume3 | 
| +///       // asynchronously to guarantee that you read the latest value | 
| +///       // set through bindings. | 
| +///       @published double volume3; | 
| const published = const PublishedProperty(); | 
|  | 
| /// An annotation used to publish a field as an attribute. See [published]. | 
| @@ -72,6 +88,45 @@ class ObserveProperty { | 
| const ObserveProperty(this._names); | 
| } | 
|  | 
| +/// Use this to create computed properties that are updated automatically. The | 
| +/// annotation includes a polymer expression that describes how this property | 
| +/// value can be expressed in terms of the values of other properties. For | 
| +/// example: | 
| +/// | 
| +///     class MyPlaybackElement extends PolymerElement { | 
| +///       @observable int x; | 
| +/// | 
| +///       // Reading xTimes2 will return x * 2. | 
| +///       @ComputedProperty('x * 2') | 
| +///       int get xTimes2 => readValue(#xTimes2); | 
| +/// | 
| +/// If the polymer expression is assignable, you can also define a setter for | 
| +/// it. For example: | 
| +/// | 
| +///       // Reading c will return a.b, writing c will update a.b. | 
| +///       @ComputedProperty('a.b') | 
| +///       get c => readValue(#c); | 
| +///       set c(newValue) => writeValue(#c, newValue); | 
| +/// | 
| +/// The expression can do anything that is allowed in a polymer expresssion, | 
| +/// even making calls to methods in your element. However, dependencies that are | 
| +/// only used within those methods and that are not visible in the polymer | 
| +/// expression, will not be observed. For example: | 
| +/// | 
| +///       // Because `x` only appears inside method `m`, we will not notice | 
| +///       // that `d` has changed if `x` is modified. However, `d` will be | 
| +///       // updated whenever `c` changes. | 
| +///       @ComputedProperty('m(c)') | 
| +///       get d => readValue(#d); | 
| +/// | 
| +///       m(c) => c + x; | 
| +class ComputedProperty { | 
| +  /// A polymer expression, evaluated in the context of the custom element where | 
| +  /// this annotation is used. | 
| +  final String expression; | 
| + | 
| +  const ComputedProperty(this.expression); | 
| +} | 
|  | 
| /// Base class for PolymerElements deriving from HtmlElement. | 
| /// | 
| @@ -174,7 +229,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { | 
| @deprecated PolymerDeclaration get declaration => _element; | 
|  | 
| Map<String, StreamSubscription> _namedObservers; | 
| -  List<Iterable<Bindable>> _observers = []; | 
| +  List<Bindable> _observers = []; | 
|  | 
| bool _unbound; // lazy-initialized | 
| PolymerJob _unbindAllJob; | 
| @@ -238,6 +293,53 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { | 
| /// prevent that from happening. | 
| bool get preventDispose => false; | 
|  | 
| +  /// Properties exposed by this element. | 
| +  // Dart note: unlike Javascript we can't override the original property on | 
| +  // the object, so we use this mechanism instead to define properties. See more | 
| +  // details in [_PropertyAccessor]. | 
| +  Map<Symbol, _PropertyAccessor> _properties = {}; | 
| + | 
| +  /// Helper to implement a property with the given [name]. This is used for | 
| +  /// normal and computed properties. Normal properties can provide the initial | 
| +  /// value using the [initialValue] function. Computed properties ignore | 
| +  /// [initialValue], their value is derived from the expression in the | 
| +  /// [ComputedProperty] annotation that appears above the getter that uses this | 
| +  /// helper. | 
| +  readValue(Symbol name, [initialValue()]) { | 
| +    var property = _properties[name]; | 
| +    if (property == null) { | 
| +      var value; | 
| +      // Dart note: most computed properties are created in advance in | 
| +      // createComputedProperties, but if one computed property depends on | 
| +      // another, the declaration order might matter. Rather than trying to | 
| +      // register them in order, we include here also the option of lazily | 
| +      // creating the property accessor on the first read. | 
| +      var binding = _getBindingForComputedProperty(name); | 
| +      if (binding == null) { // normal property | 
| +        value = initialValue != null ? initialValue() : null; | 
| +      } else { | 
| +        value = binding.value; | 
| +      } | 
| +      property = _properties[name] = new _PropertyAccessor(name, this, value); | 
| +    } | 
| +    return property.value; | 
| +  } | 
| + | 
| +  /// Helper to implement a setter of a property with the given [name] on a | 
| +  /// polymer element. This can be used on normal properties and also on | 
| +  /// computed properties, as long as the expression used for the computed | 
| +  /// property is assignable (see [ComputedProperty]). | 
| +  writeValue(Symbol name, newValue) { | 
| +    var property = _properties[name]; | 
| +    if (property == null) { | 
| +      // Note: computed properties are created in advance in | 
| +      // createComputedProperties, so we should only need to create here | 
| +      // non-computed properties. | 
| +      property = _properties[name] = new _PropertyAccessor(name, this, null); | 
| +    } | 
| +    property.value = newValue; | 
| +  } | 
| + | 
| /// If this class is used as a mixin, this method must be called from inside | 
| /// of the `created()` constructor. | 
| /// | 
| @@ -291,6 +393,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { | 
| makeElementReady() { | 
| if (_readied) return; | 
| _readied = true; | 
| +    createComputedProperties(); | 
|  | 
| // TODO(sorvell): We could create an entry point here | 
| // for the user to compute property values. | 
| @@ -554,7 +657,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { | 
| syntax = element.syntax; | 
| } | 
| var dom = t.createInstance(this, syntax); | 
| -    registerObservers(getTemplateInstanceBindings(dom)); | 
| +    _observers.addAll(getTemplateInstanceBindings(dom)); | 
| return dom; | 
| } | 
|  | 
| @@ -640,7 +743,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { | 
| if (observe != null) { | 
| var o = _propertyObserver = new CompoundObserver(); | 
| // keep track of property observer so we can shut it down | 
| -      registerObservers([o]); | 
| +      _observers.add(o); | 
|  | 
| for (var path in observe.keys) { | 
| o.addPath(this, path); | 
| @@ -656,10 +759,13 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { | 
| if (_propertyObserver != null) { | 
| _propertyObserver.open(notifyPropertyChanges); | 
| } | 
| -    // Dart note: we need an extra listener. | 
| -    // see comment on [_propertyChange]. | 
| + | 
| +    // Dart note: we need an extra listener only to continue supporting | 
| +    // @published properties that follow the old syntax until we get rid of it. | 
| +    // This workaround has timing issues so we prefer the new, not so nice, | 
| +    // syntax. | 
| if (_element._publish != null) { | 
| -      changes.listen(_propertyChange); | 
| +      changes.listen(_propertyChangeWorkaround); | 
| } | 
| } | 
|  | 
| @@ -705,19 +811,26 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { | 
| } | 
| } | 
|  | 
| -  // Dart note: this is not called by observe-js because we don't have | 
| -  // the mechanism for defining properties on our proto. | 
| -  // TODO(jmesserly): this has similar timing issues as our @published | 
| -  // properties do generally -- it's async when it should be sync. | 
| -  void _propertyChange(List<ChangeRecord> records) { | 
| +  // Dart note: this workaround is only for old-style @published properties, | 
| +  // which have timing issues. See _bindOldStylePublishedProperty below. | 
| +  // TODO(sigmund): deprecate this. | 
| +  void _propertyChangeWorkaround(List<ChangeRecord> records) { | 
| for (var record in records) { | 
| if (record is! PropertyChangeRecord) continue; | 
|  | 
| -      final name = smoke.symbolToName(record.name); | 
| -      final reflect = _element._reflect; | 
| -      if (reflect != null && reflect.contains(name)) { | 
| -        reflectPropertyToAttribute(name); | 
| -      } | 
| +      var name = record.name; | 
| +      // The setter of a new-style property will create an accessor in | 
| +      // _properties[name]. We can skip the workaround for those properties. | 
| +      if (_properties[name] != null) continue; | 
| +      _propertyChange(name); | 
| +    } | 
| +  } | 
| + | 
| +  void _propertyChange(Symbol nameSymbol) { | 
| +    var name = smoke.symbolToName(nameSymbol); | 
| +    var reflect = _element._reflect; | 
| +    if (reflect != null && reflect.contains(name)) { | 
| +      reflectPropertyToAttribute(name); | 
| } | 
| } | 
|  | 
| @@ -751,19 +864,97 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { | 
| } | 
| } | 
|  | 
| -  void registerObservers(Iterable<Bindable> observers) { | 
| -    _observers.add(observers); | 
| +  emitPropertyChangeRecord(Symbol name, newValue, oldValue) { | 
| +    if (identical(oldValue, newValue)) return; | 
| +    _propertyChange(name); | 
| } | 
|  | 
| -  void closeObservers() { | 
| -    _observers.forEach(closeObserverList); | 
| -    _observers = []; | 
| +  bindToAccessor(Symbol name, Bindable bindable, {resolveBindingValue: false}) { | 
| +    // Dart note: our pattern is to declare the initial value in the getter.  We | 
| +    // read it via smoke to ensure that the value is initialized correctly. | 
| +    var oldValue = smoke.read(this, name); | 
| +    var property = _properties[name]; | 
| +    if (property == null) { | 
| +      // We know that _properties[name] is null only for old-style @published | 
| +      // properties. This fallback is here to make it easier to deprecate the | 
| +      // old-style of published properties, which have bad timing guarantees | 
| +      // (see comment in _PolymerBinding). | 
| +      return _bindOldStylePublishedProperty(name, bindable, oldValue); | 
| +    } | 
| + | 
| +    property.bindable = bindable; | 
| +    var value = bindable.open(property.updateValue); | 
| + | 
| +    if (resolveBindingValue) { | 
| +      // capture A's value if B's value is null or undefined, | 
| +      // otherwise use B's value | 
| +      var v = (value == null ? oldValue : value); | 
| +      if (!identical(value, oldValue)) { | 
| +        bindable.value = value = v; | 
| +      } | 
| +    } | 
| + | 
| +    property.updateValue(value); | 
| +    var o = new _CloseOnlyBinding(property); | 
| +    _observers.add(o); | 
| +    return o; | 
| +  } | 
| + | 
| +  // Dart note: this fallback uses our old-style binding mechanism to be able to | 
| +  // link @published properties with bindings. This mechanism is backwards from | 
| +  // what Javascript does because we can't override the original property. This | 
| +  // workaround also brings some timing issues which are described in detail in | 
| +  // dartbug.com/18343. | 
| +  // TODO(sigmund): deprecate old-style @published properties. | 
| +  _bindOldStylePublishedProperty(Symbol name, Bindable bindable, oldValue) { | 
| +    // capture A's value if B's value is null or undefined, | 
| +    // otherwise use B's value | 
| +    if (bindable.value == null) bindable.value = oldValue; | 
| + | 
| +    var o = new _PolymerBinding(this, name, bindable); | 
| +    _observers.add(o); | 
| +    return o; | 
| +  } | 
| + | 
| +  _getBindingForComputedProperty(Symbol name) { | 
| +    var exprString = element._computed[name]; | 
| +    if (exprString == null) return null; | 
| +    var expr = PolymerExpressions.getExpression(exprString); | 
| +    return PolymerExpressions.getBinding(expr, this, | 
| +        globals: element.syntax.globals); | 
| +  } | 
| + | 
| +  createComputedProperties() { | 
| +    var computed = this.element._computed; | 
| +    for (var name in computed.keys) { | 
| +      try { | 
| +        // Dart note: this is done in Javascript by modifying the prototype in | 
| +        // declaration/properties.js, we can't do that, so we do it here. | 
| +        var binding = _getBindingForComputedProperty(name); | 
| + | 
| +        // Follow up note: ideally we would only create the accessor object | 
| +        // here, but some computed properties might depend on others and | 
| +        // evaluating `binding.value` could try to read the value of another | 
| +        // computed property that we haven't created yet. For this reason we | 
| +        // also allow to also create the accessor in [readValue]. | 
| +        if (_properties[name] == null) { | 
| +          _properties[name] = new _PropertyAccessor(name, this, binding.value); | 
| +        } | 
| +        bindToAccessor(name, binding); | 
| +      } catch (e) { | 
| +        window.console.error('Failed to create computed property $name' | 
| +            ' (${computed[name]}): $e'); | 
| +      } | 
| +    } | 
| } | 
|  | 
| -  void closeObserverList(Iterable<Bindable> observers) { | 
| -    for (var o in observers) { | 
| +  // Dart note: to simplify the code above we made registerObserver calls | 
| +  // directly invoke _observers.add/addAll. | 
| +  void closeObservers() { | 
| +    for (var o in _observers) { | 
| if (o != null) o.close(); | 
| } | 
| +    _observers = []; | 
| } | 
|  | 
| /// Bookkeeping observers for memory management. | 
| @@ -800,7 +991,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { | 
| ///       bindProperty(#myProperty, | 
| ///           new PathObserver(this, 'myModel.path.to.otherProp')); | 
| ///     } | 
| -  Bindable bindProperty(Symbol name, Bindable bindable, {oneTime: false}) { | 
| +  Bindable bindProperty(Symbol name, bindableOrValue, {oneTime: false}) { | 
| // Dart note: normally we only reach this code when we know it's a | 
| // property, but if someone uses bindProperty directly they might get a | 
| // NoSuchMethodError either from the getField below, or from the setField | 
| @@ -808,23 +999,20 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { | 
| // difference from Polymer.js behavior. | 
|  | 
| if (_bindLog.isLoggable(Level.FINE)) { | 
| -      _bindLog.fine('bindProperty: [$bindable] to [$_name].[$name]'); | 
| +      _bindLog.fine('bindProperty: [$bindableOrValue] to [$_name].[$name]'); | 
| } | 
|  | 
| -    // capture A's value if B's value is null or undefined, | 
| -    // otherwise use B's value | 
| -    // TODO(sorvell): need to review, can do with ObserverTransform | 
| -    var v = bindable.value; | 
| -    if (v == null) { | 
| -      bindable.value = smoke.read(this, name); | 
| +    if (oneTime) { | 
| +      if (bindableOrValue is Bindable) { | 
| +        _bindLog.warning('bindProperty: expected non-bindable value ' | 
| +            'on a one-time binding to [$_name].[$name], ' | 
| +            'but found $bindableOrValue.'); | 
| +      } | 
| +      smoke.write(this, name, bindableOrValue); | 
| +      return null; | 
| } | 
|  | 
| -    // TODO(jmesserly): we need to fix this -- it doesn't work like Polymer.js | 
| -    // bindings. https://code.google.com/p/dart/issues/detail?id=18343 | 
| -    // apply Polymer two-way reference binding | 
| -    //return Observer.bindToInstance(inA, inProperty, observable, | 
| -    //    resolveBindingValue); | 
| -    return new _PolymerBinding(this, name, bindable); | 
| +    return bindToAccessor(name, bindableOrValue, resolveBindingValue: true); | 
| } | 
|  | 
| /// Attach event listeners on the host (this) element. | 
| @@ -997,9 +1185,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { | 
| _STYLE_CONTROLLER_SCOPE); | 
| applyStyleToScope(style, scope); | 
| // cache that this style has been applied | 
| -    Set styles = _scopeStyles[scope]; | 
| -    if (styles == null) _scopeStyles[scope] = styles = new Set(); | 
| -    styles.add('$_name$name'); | 
| +    styleCacheForScope(scope).add('$_name$name'); | 
| } | 
|  | 
| Node findStyleScope([node]) { | 
| @@ -1012,9 +1198,23 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { | 
| return n; | 
| } | 
|  | 
| -  bool scopeHasNamedStyle(Node scope, String name) { | 
| -    Set styles = _scopeStyles[scope]; | 
| -    return styles != null && styles.contains(name); | 
| +  bool scopeHasNamedStyle(Node scope, String name) => | 
| +      styleCacheForScope(scope).contains(name); | 
| + | 
| +  Map _polyfillScopeStyleCache = {}; | 
| + | 
| +  Set styleCacheForScope(Node scope) { | 
| +    var styles; | 
| +    if (_hasShadowDomPolyfill) { | 
| +      var name = scope is ShadowRoot ? scope.host.localName | 
| +          : (scope as Element).localName; | 
| +      var styles = _polyfillScopeStyleCache[name]; | 
| +      if (styles == null) _polyfillScopeStyleCache[name] = styles = new Set(); | 
| +    } else { | 
| +      styles = _scopeStyles[scope]; | 
| +      if (styles == null) _scopeStyles[scope] = styles = new Set(); | 
| +    } | 
| +    return styles; | 
| } | 
|  | 
| static final _scopeStyles = new Expando(); | 
| @@ -1079,12 +1279,14 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { | 
| } | 
| } | 
|  | 
| -// Dart note: Polymer addresses n-way bindings by metaprogramming: redefine | 
| -// the property on the PolymerElement instance to always get its value from the | 
| -// model@path. We can't replicate this in Dart so we do the next best thing: | 
| -// listen to changes on both sides and update the values. | 
| -// TODO(jmesserly): our approach leads to race conditions in the bindings. | 
| -// See http://code.google.com/p/dart/issues/detail?id=13567 | 
| +// Dart note: this is related to _bindOldStylePublishedProperty. Polymer | 
| +// addresses n-way bindings by metaprogramming: redefine the property on the | 
| +// PolymerElement instance to always get its value from the model@path. This is | 
| +// supported in Dart using a new style of @published property declaration using | 
| +// the `readValue` and `writeValue` methods above. In the past we used to work | 
| +// around this by listening to changes on both sides and updating the values. | 
| +// This object provides the hooks to do this. | 
| +// TODO(sigmund,jmesserly): delete after a deprecation period. | 
| class _PolymerBinding extends Bindable { | 
| final Polymer _target; | 
| final Symbol _property; | 
| @@ -1100,6 +1302,8 @@ class _PolymerBinding extends Bindable { | 
| void _updateNode(newValue) { | 
| _lastValue = newValue; | 
| smoke.write(_target, _property, newValue); | 
| +    // Note: we don't invoke emitPropertyChangeRecord here because that's | 
| +    // done by listening on changes on the PolymerElement. | 
| } | 
|  | 
| void _propertyValueChanged(List<ChangeRecord> records) { | 
| @@ -1127,6 +1331,24 @@ class _PolymerBinding extends Bindable { | 
| } | 
| } | 
|  | 
| +// Ported from an inline object in instance/properties.js#bindToAccessor. | 
| +class _CloseOnlyBinding extends Bindable { | 
| +  final _PropertyAccessor accessor; | 
| + | 
| +  _CloseOnlyBinding(this.accessor); | 
| + | 
| +  open(callback) {} | 
| +  get value => null; | 
| +  set value(newValue) {} | 
| +  deliver() {} | 
| + | 
| +  void close() { | 
| +    if (accessor.bindable == null) return; | 
| +    accessor.bindable.close(); | 
| +    accessor.bindable = null; | 
| +  } | 
| +} | 
| + | 
| bool _toBoolean(value) => null != value && false != value; | 
|  | 
| final Logger _observeLog = new Logger('polymer.observe'); | 
|  |