Observables

:warning: Backward incompatible changes prototyped

This is a proposal to replace the existing change listener implementation and interface in the next major version of Collections with a design more consistent with the use and performance needs of FRB. There are multiple motivations for this change, and implications for the designs built on top of these observers.

The design is intended to flush better with patterns in FRB, and to establish a new pattern that will be useful for improving the performance of FRB. Instead of returning a `cancel` closure, the `observe` methods return a reusable observer object. These objects are retained on a free list after cancelation to avoid garbage collector churn. The observer object itself has properties corresponding to all of the state that was originally captured by cancel closures within FRB. These new observer primitives in Collections also stackable. A handler may return a child observer and the parent will cancel the child before dispatching a new change notification. I intend to eventually refactor FRB to use this pattern.

The `add/remove` listener interfaces are replaced with `observe` methods that return “observer” objects. The observer  “handle” can be retained for its `cancel` method. The old design was an analogy to `add` and `remove` `EventListener`. The new design is more like `setTimeout` and `clearTimeout`, except the token returned by observe methods is an object instead of a magic number, and the token itself has the `cancel` method. We call the token an “observer”.

The ability to dispatch on a conventionally-named method of a handler object has been retained. This is a useful pattern for the Cocoa-style MVC employed by MontageJS. However, the dispatch method name can now be overridden with the `handlerMethodName` property of an observer.

Inconsistencies in the handler method name conventions have been resolved. A “capturing” change listener used to be of the form “addBeforeOwnPropertyChangeListener”. This has been altered to “observePropertyWillChange”, to be consistent with the corresponding handler method name, “handlePropertyWillChange”. Also, named property change handlers have been changed from the form “handleFooChange” to “handleFooPropertyChange” to avoid a collision for the property name “property”, which would now be “handlePropertyPropertyChange” and distinct from the generic property change handler fallback, “handlePropertyChange”. This also establishes a stronger convention—all change dispatch handler methods are infixed with the name of the kind of change: `Property`, `Range`, or `Map`. I would hope that events will adopt this convention in MontageJS, e.g., “handleActionEvent” instead of “handleAction”.

All change handlers, regardless of whether they dispatch before or after a change, now receive both the old and new values. So, property change handlers receive `(plus, minus, key, object)` instead of just `(minus, key, object)` before and `(plus, key, object)` after. This allows more to be done with a single observer, without coordinating state between change- and will-change- observers. In addition, map change handlers now receive the “type” of change: “create”, “update”, or “delete”. So, the old interface was `(minus, key, map`) before and `(plus, key, map)` after. Both change notifications were necessary to infer how to project the change onto another map, and neither were sufficient to distinguish adding `undefined` from deleting an entry. The new interface is `(plus, minus, key, type, map)`.

Also, all of the new observers accept a `note` argument. The `note` is a slot retained on `observer` objects for the user and is otherwise not used internally. It is intended to provide information to assist inspectors and serializers. Particularly, when FRB installs an observer, it will use the note to associate the observer with a node of a live FRB expression, so an inspector can reveal, by enumerating the notes of all observers on an object, in what bindings the object participates. The MontageJS serializer might take advantage of this note to distinguish ephemeral observers from those that were mentioned in the serialization document that instantiated the object.