Thursday, March 22, 2012

Really, Really Removing Event Handlers in Dart

‹prev | My Chain | next›

Up tonight a quick follow-up to yesterday's post on Dart event handlers. It was pointed out in comments by Ernesto Oltra that the manner in which I was removing handlers might not be doing what I thought it was doing.

That is easy enough to test, I add a print statement to my draw/resize hander:
  _removeHandlers() {
    window.
      on.
      resize.
      remove(_drawBackground);
  }

  _drawBackground([_]) {
    print('_drawBackground');
    // ...
  }
Then I create the modal dialog to which these handlers are attached and remove it it immediately. Then I resize the browser window. If the events had been removed, then I should not see any print() output. But I do see it:


Dang it.

This seems to be one of those interesting edge cases of a new language. The problem is that Dart has not yet decided how to tell if functions / methods equal each other. It seems a reasonable expectation that the following two should refer to the same method (_drawBackground):
  _attachHanders() {
    // ...
    window.
      on.
      resize.
      add(_drawBackground);
  }

  _removeHandlers() {
    window.
      on.
      resize.
      remove(_drawBackground);
  }
Currently they do not. The reasoning is that whatever closures are created by the method might make it different. In other words _drawBackground == _drawBackground // => false because of the potential for closures.

Until this issue is resolved, I need an alternate approach to force Dart to think these are the same handler. Per that ticket, this involves assigning the handler to a variable for which the equality it less ambiguous:
class ModalDialog implements Element {
  Element el, bg;
  var resizeHandler;

  ModalDialog(): this.tag('div');

  ModalDialog.tag(String tag) {
    el = new Element.tag(tag);
    resizeHandler = _drawBackground;
  }

  _attachHanders() {
    // ...
    window.
      on.
      resize.
      add(resizeHandler);
  }

  _removeHandlers() {
    window.
      on.
      resize.
      remove(resizeHandler);
  }
  //...
}
The value of the variable resizeHandler is a reference to the method, not the method itself. It seems a subtle distinction, but it does the trick. After closing my modal, no amount of resizing generates a call to the resizing handler:


It will be interesting to see how Dart team resolves this. My original expectation really seems reasonable, but I have no qualms with the bug languishing. In fact, I rather appreciate that there are no rushes to address gnarly cases like this. I am happy to work around it for now if that means a better ultimate solution. Still, it will make for interesting writing in Dart for Hipsters' Events chapter.


Day #333

2 comments:

  1. Replies
    1. Nope, it is still not fixed. It doesn't seem as though it is likely to be fixed any time soon. The above workaround remains the only way to remove event handlers, unfortunately.

      There is a "wontfix" dartlang bug at: https://code.google.com/p/dart/issues/detail?id=144

      Delete