block-lambda revival

Mark S. Miller erights at google.com
Thu Jun 23 17:16:55 PDT 2011


[+stay]

Another bit of evidence for lexical this, and thus for block lambdas over
arrow functions or simple # functions.

At <
http://wiki.ecmascript.org/doku.php?id=harmony:proxies&rev=1308499413&do=diff>
I corrected a bug noticed just now by Mike Stay (cc'ed). The bug dates from
<
http://wiki.ecmascript.org/doku.php?id=harmony:proxies&rev=1280925681#trap_defaults>
in August of 2010, more than 10 months ago, when Tom van Cutsem wrote:

    keys: function() {
      return this.getOwnPropertyNames().filter(
        function (name) { return
this.getOwnPropertyDescriptor(name).enumerable });
    }

This bug was written by one of the most talented and careful programmers I
have ever met. The page it appears in has been carefully examined by many
experts (not just official experts -- real experts) and a large community of
talented people, guiding at least three implementations of the proxy system.
The bug was only noticed by Mike Stay while starting the newest of these
implementation efforts, emulating proxies on old browsers within ES5/3.

Most JavaScript code will be much less reviewed than this, and by a
community less expert than ourselves in the peculiarities of the language.
We need to ask, why was this bug so easy for an expert to make and so hard
for a community of experts to catch? My guess is that it's because
Array.prototype.filter "feels" like a control structure and the anon
function we're calling it with "feels" like a control structure block, even
though we know that we know otherwise. When we see the "this" inside and try
to figure out what it means, we search outward for a "function" and our eye
often catches the wrong one.


Let's see what Tom might have written with three of the other function-like
proposals. To be fair, I'll assume here that "return" can be omitted in all.

Arrow functions:

    keys: function() {
      return this.getOwnPropertyNames().filter(
        (name) -> this.getOwnPropertyDescriptor(name).enumerable );
    }

Simple # functions

    keys: function() {
      return this.getOwnPropertyNames().filter(
        #(name) { this.getOwnPropertyDescriptor(name).enumerable });
    }

block lambdas

    keys: function() {
      return this.getOwnPropertyNames().filter { |name|
        this.getOwnPropertyDescriptor(name).enumerable
      }
    }

The first and obvious point I'm making is that Tom would not have made this
particular mistake with block lambdas, but I recognize that this argument
cuts both ways. Other uses may have the opposite hazard, and we need to
examine this as well. The new point is that arrow functions and simple #
functions make the original hazard *worse*, because, like "function", they
still rebind this. But by being less verbose than "function", it's even
easier for the eye to miss them when seeing a "this" in their body and
trying to determine what it means.

The more I think about this, the more I'm inclined to believe that, for
functions which rebind "this", the verbosity of "function" is a virtue. As
fallible programmers, we can only afford a more compact function notation
for defining functions with lexical "this" -- like block lambdas.

-- 
  Cheers,
  --MarkM
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110623/aaf4ebec/attachment-0001.html>


More information about the es-discuss mailing list