I must say you globally got my point (even if, after re-reading it, it wasn't 
as clear as I intended). I hope others did, too.

To respond to your questions :

(1) On the usage of the arobase (@) symbol
  The @ is used in some languages as a function introductory keyword. Have a 
look at the very popular (among engineers) Matlab/Octav, for exemple. To me, it 
also carry a vlid semantic since "At X corresponds X.toString()" is a nice way 
to say "@(X) X.toString()".

  I've had a look at the current private name proposal, and, since last time I 
checked, there's still no mention of the @ symbol in it. If I guess correctly, 
it could replace the # sign used currently on the page. In that case, I don't 
see where's the problem with using the @() syntax since you can't actuall call 
the # symbol in the current proposal, you just need to access his ‘properties’.

  By the way, I don't say we should use @, just that it's a possible choice 
(and that if # has a semantic issue that would make it a bad choice, it can be 
used instead). I’ve been using the @ symbol quite a lot in the past to 
introduce functions so it feels natural for me (don’t take me responsible if I 
continue to use it in my mails) but if the comitee choose to use # (or another 
symbol like %, µ or § (which is the key just after the opening parenthesis on 
my keyboard BTW)), I would be perfectly happy.

(2) Arrow between args and body
  Would be complex to parse. I don’t think it’s possible, and even if it is, it 
could be horribly confusing in some cases :

  ? array.filter((x)=>x<5) 
  ? array.filter((x)=>(x<5))
  ? array.filter((x)=>{return x<5;})

  var list = { 
      ... 
      append: (x) => {
          list.add(x,list.length);
      }
      ...
  }

  ?

(2) Function, block-lambda semantics

  Maybe I wasn’t that clear on the point, but something I hate is 
non-future-proof/unstable coding. When I write a piece of code, I want it to be 
as maintainable as possible. By maintainable, I mean that if I need to change 
the code, a small change should never trigger changes at different locations in 
my code. Small change, small fix.

  The problem with the block-lambda used as a ‘local function’ (sorry, I don’t 
see a better way to define the concept, ie a function which is only used in an 
action-related, controlled context) is that a small change could require major 
rewrite.

  Let’s imagine that I wrote that code :

    arrary.map({|x|    while(x.previousSibling) x=x.previousSibling;    });

  Then, let’s imagine that I should change my code to include an early return. 
Using block-lambda, it can be rather complex.
    array.map({|x|    
        let shouldReturn=false;
        while(!shouldReturn && x.previousSibling) {
            if(isValidStart(x)) { shouldReturn=true; }
            else { x=x.previousSibling; }
       }
        x;
    })
  Boom, the code has become very complex and is not easily readable anymore. 
Even if I wanted to modify my code to transform the block-lambda in a function, 
it would involve a lot of rewrite (changes are highlighted here, but I think if 
I face the case, I just delete the whole code and restart from scratch) :
    array.map(function(x) {
        while(x.previousSibling) {
            if(isValidStart(x)) return x;
            x=x.previousSibling;
        }
        return x;
    });

  But, according to me, if a small change can trigger a block-lambda to become 
a function, it’s because it should not have been a block lambda from start. It 
should have been a function.

  Lets consider the case where we use a short function notation instead, from 
beginning :
    array.map(@(x) { 
        while(x.previousSibling) { x=x.previousSibling; }
        return x; 
    }
  It’s a big longer but it’s futur-proof. To make my small change, I just have 
to add one line of code.
    array.map(@(x) {
        while(x.previousSibling) {
            if(isValidStart(x)) return x;
            x=x.previousSibling;
        }
        return x;
    });
  For the first time, the code was stable. A small change only shifted slightly 
the balance. 

  I can acomodate with ‘function’, but, let’s face it, in some simpler cases, 
if I don’t have a short function notation, I’ll use a block-lambda and will 
face the problem. And be sure I’ll dislike it :-D

  Even allowing the @(x) x.toString() syntax is not a problem since if I need 
to change the expression into a list of statement, there’s just one place to 
perform the changes (I have to replace x.toString() with a new code), so I can 
write my code in one continuous typing stream, and I don’t have to use the 
mouse (or CTRL+Arrows) to move the spot to different places. An expression has 
to be small anyway so I don’t loose a lot of code even if I choose to scratch & 
redo. The @ and the arguments are already there.
(3) Short function ‘desugaring’ preference
  If I could choose, I would set the short function syntax to imply automatic 
binding. But since it makes them unusable for script minizers without checking 
if ‘this’ is used in the function or not, I guess I can live without that (to 
the condition that I can do that: @(this=this, x) this.transform(x)).

I hope I’ve been more clear than in my previous mail,
François




-----Message d'origine----- 
From: Brendan Eich 
Sent: Friday, January 20, 2012 12:28 AM 
To: François REMY 
Cc: Axel Rauschmayer ; Andreas Rossberg ; Oliver Hunt ; es-discuss Steen 
Subject: Re: Block lambda is cool, its syntax isn't 

> 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

Reply via email to