Block lambda is cool, its syntax isn't

François REMY fremycompany_pub at yahoo.fr
Thu Jan 19 12:19:04 PST 2012


It may be just a personnal taste, but I've to agree the current proposal 
(#() ...) seems very appealing to me. I did not respond to your mail 
proposing to use the Arrow syntax because it seems obscure to me. The 
distinction between "normal" and "fat" arrow is thin, does not make sense. 
You either need a function-object (which doesn't have 'this' mapping, has 
expandos) or a local-function (which has 'this' mapping, just need to be a 
[Call] target). If you need the first, you need a traditionnal function 
since you need something not-frozen that can be added to objects as a 
property at a later time. If you want 'this' mapping, you need something 
that only makes sense in a local context.

Additionnaly, the arrow syntax is illogical. You usually say "I want a 
function of (X,Y) which returns X+Y" or "I want to transform X in 
X.toString", not "From X, I want to get X.toString()".

Freezing a local function seems as acceptable to me as it seemed to others. 
A LF should only be used in a controlled context where the function itself 
is just used as a function, not an object. But if it's not acceptable to 
other members, I'm not against a @(x) syntax that does not offer frozen 
functions (but I think it's a missed optimization opportunity). The point 
about Conditionnal Compiling in IE is not valid anymore since Microsoft has 
deleted HTML Conditionnal Comments because they were not standards (even if 
they were used a lot), so I don't think the obscure and fewly used JScript 
CC are meant to stay, especially if it hurts another proposal.

In my view of the thing, a local function should be used as a function in 
the mathematical sense of the term: you give a parameter, it returns its 
image by the function.

The cases we are trying to solve:

    var inc=#(x) x+1;

    array.map(#(x) x.toString());

    array.filter(#(x) isValid(x));

    array.map(#(x) {
        while(x.previousSibling) x=x.previousSibling;
        return x;
    });

For example, I don't see this as a good use-case of a LocalFunction :

    ...
    refreshLayout: function(e) {
        ...
        requestAnimationFrame(#(e) this.refreshLayout(e));
    }
    ...

It should be a block lambda instead, because it's meant to 'continue' the 
current function in a sort of async while(true) loop.

    ...
    refreshLayout: function(e) {
        ...
        requestAnimationFrame({|e| this.refreshLayout(e) });
    }
    ...

For all of the use cases where a "mathematical function" is requied, you 
just need some valid [Call]-able item. You will never add expandos on an 
function you don't know (ie that you received as a parameter). You'll wrap 
it before, if you really need that. If you want the full flexibility of a 
function-as-an-object, it means you need a 'true function'; LF are not meant 
to replace functions in the long run, they are made to serve the case where 
you want a short, action-related, contextual function. That means 'this' 
binding, if needed, just like it's in languages like dotNET.

However, I would like to hear more about the specific reasons that led Arv 
and Alex think a LF should not be frozen.

Regards,
François



PS: The synax I speak about for LocalFunctions would be:

<LocalFunctionExpression>:
    '#(' <argument-list> ')' <expression>
    or
    '#(' <argument-list> ') {' <statements>* '}'

They would be 'bound-this' if there's a 'this' in their body, but can be 
left unbounded if there's no since it has no visible effet. If they don't 
reference variables of a scope, they should not use reference scope and may 
be reused accross function calls.




-----Message d'origine----- 
From: Brendan Eich
Sent: Thursday, January 19, 2012 8:27 PM
To: Axel Rauschmayer ; Andreas Rossberg
Cc: François REMY ; Oliver Hunt ; es-discuss Steen
Subject: Re: Block lambda is cool, its syntax isn't

Axel Rauschmayer <mailto:axel at rauschma.de>
January 19, 2012 9:31 AM

Rationale: wouldn’t freezing by default be OK for 98% of the cases? If
you want anything else, you can use a traditional function. Then the
above syntax as the only function shorthand would be OK.


First, #(params) { body } was proposed by Arv and Alex:

http://wiki.ecmascript.org/doku.php?id=strawman:shorter_function_syntax

Arv and Alex feel strongly that the shorter function syntax (anything
shortening 'function' syntax) must not freeze by default.

There was lack of clarity about whether completion value as implicit
return value was part of the proposal. If so, controvery, since there is
a completion value leak hazard. TC39 seems to agree the solution there
is something with different look & feel, such as block-lambdas.

But, making a one-char grawlix shorthand for 'function' while still
requiring 'return' is not considered enough of a shorthand. A possible
cure here is to support an alternative body syntax: #(params) expr.
However, this inverts precedence if done naively. It also runs into
trouble trying to prefer an object literal over a block statement. I've
worked on both of these in the context of

http://wiki.ecmascript.org/doku.php?id=strawman:arrow_function_syntax

This superseded shorter_function_syntax, but ran into grammatical issues
that have vexed it.

But notice that throughout this, no one advancing a proposal advocated
freezing by default. JS developers use function objects as mutable
objects. Not just to set .prototype, also to decorate with ad-hoc and
meta-data properties. Freezing is not wanted by default.

I agree that for block-lambdas it's easier to say "freeze by default".
For merely "shorter function syntax", no. Functions are mutable objects
by default in JS. This matters for minifiers, which may not be able to
see all the mutations but would love to use shorter syntax for
'function' syntax, blindly.

/be 



More information about the es-discuss mailing list