three small proposals: the bikeshed cometh!

Mark S. Miller erights at
Thu Apr 29 11:51:06 PDT 2010

On Thu, Apr 29, 2010 at 12:25 AM, Alex Russell <alex at> wrote:

>  node.addEventListener("click", bang(obj, "method"));
>  // works!
>  node.removeEventListener("click", bang(obj, "method"));

On Thu, Apr 29, 2010 at 10:42 AM, Tom Van Cutsem <tomvc at> wrote:

> node.addEventListener("click", bind(obj).method );
> node.removeEventListener("click", bind(obj).method );

Both techniques cache the bound method, in order to preserve identity, so
that the above examples work.

When caching, one should always worry about cache invalidation. Say that obj
inherits from Foo.prototype and that both examples are thereby caching
Foo.prototype.method as bound to obj. Neither Alex nor Tom are first
verifying that Foo.prototype.method is a non-writable, non-configurable data
property, and so neither are justified in assuming its value may not change.
Between the two statements above, what happens if

    Foo.prototype.method = function(){ /* some other function */ };

? Because Alex's cache is indexed by the identity of obj and by the name
"method", bang will return a stale result and the removeEventListener will
succeed when it shouldn't. Because Tom's cache is indexed by the identity of
obj and the identity of the function being bound, the removeEventListener
will properly fail.

I verbally verified with Tom just now that he hadn't thought about this
cache invalidation issue at all. I think this corroborates that the
EphemeronTable-based technique is more robust -- it did the right thing for
the right reasons even for cases that weren't thought about at the time. (Of
course, no matter how robust the patterns being used, please *always* think
about cache invalidation when designing a cache of any kind.)

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list