François REMY <mailto:fremycompany_...@yahoo.fr>
January 19, 2012 12:19 PM
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.
Agreed, and that is another problem plaguing arrow function syntax as
proposed. But if we rescue it by moving the arrow up front, we may solve
this problem by dropping fat arrow. "Shorter function syntax" does not
have to include "shorter .bind(o) syntax".
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).
We can't guess and I would not assume a local (nested, you mean?)
function wants lexical |this| by default, overridden only by callee-base
|this| when/if the nested function is called as a method. Mark Miller
showed the problem:
https://mail.mozilla.org/pipermail/es-discuss/2011-November/018186.html
in reply to
https://mail.mozilla.org/pipermail/es-discuss/2011-November/018183.html
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.
You mean a block-lambda? I agree.
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()".
I'm not sure what you mean here by "illogical" and your verbal
expansions -- are you saying the arrow should come in between params and
body? Yes, that is nicer and Jeremy Ashkenas followed that design (used
in other languages of course) for that reason. But it makes for grammar
trouble for two reasons:
1. (params) looks like a comma expression. We can parse it as such and
then validate it using "supplemental syntax" as for destructuring, but
it is a bit future-hostile.
2. If we want an expression body alternate syntax that prefers object
literals over body blocks, we have to resolve this conflict:
http://wiki.ecmascript.org/doku.php?id=strawman:block_vs_object_literal
Doing so is even more future-hostile in light of the new object literal
extensions in ES6.
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).
Again, @ is wanted for private names -- all the few unused ASCII
punctuators are wanted. Why are you insisting on @ here? It's not
particularly associated with functions in other languages, or suggestive
of functions.
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.
JS practice varies wildly. No developer consensus on this point.
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;
});
This case is not like the one you showed earlier, and not so clearly bad
for block-lambda. There is only one return, it's at the bottom, so
completion value as implicit return value in a block-lambda wins:
array.map({ |x|
while(x.previousSibling) x=x.previousSibling;
x;
});
It's not a requirement either way, of course.
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.
Oh but here is a case where you advocate a block-lamdba for an "async
callback". IIRC earlier you wrote that block-lambdas should be used for
sync callbacks. I may have misread you though.
I dont believe there's a hard and fast rule. Of course, the block-lambda
cannot break/continue/return if the enclosing function activation is no
more.
...
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).
No, but local functions are decorated with expandos in their local scope.
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.
We don't want a third kind of function (LF?). We just want shorter
syntax. If freezing needs shorter syntax, # as prefix composes.
However, I would like to hear more about the specific reasons that led
Arv and Alex think a LF should not be frozen.
I already wrote it: this is just proposed shorter syntax for 'function'.
Shortening shouldn't freeze by default. That means the use-cases today
for mutated functions cannot use the shorter syntax, for no reason other
than your aesthetics about "mathematical functions", etc.
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.
<expression> doesn't work as I've argued, due to precedence inversion --
we cannot make Expression ::= LocalFunctionExpression. We should aim to
put LocalFunctionExpression at AssignmentExpression precedence, which
requires the expression-body form to be
'#(' <argument-list> ')' <assignment-expression>
/be
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss