[Arrow function syntax] Move Arrow to head to fix ArrowFormalParameters issues
one thing that stands out in your proposal is that there doesn't appear to be any way to write a recursive arrow function.
Here is one way it might be done:
higher(->: fact (n) n<=1?1:n*fact(n-1));
or possibly
higher(->@ fact (n) n<=1?1:n*fact(n-1));
(in either case the 3 character arrow sequence would be one token)
It seems you're rethrowing the -> vs the @ syntax debate. (replace -> by @
in your proposal, you'll get the initial proposal I did)
setTimeout(@alert('2s elapsed'), 2000);
setTimeout(@@this.performAction(), 5000);
function getReference() { return @@this; }
var props = objs.map(@(x) x.property);
// possible additionnal shorthand for simple cases:
// var props = objs.map(@.property);
// var getValues = objs.map(@.getValue());
The syntax would be exactly the same as you did propose :
ShortFunctionSymbol FormalParametersOpt InitialValue
ShortFunctionSymbol FormalParametersOpt BlockOpt
It seems easier to parse since the current arrows syntax makes it impossible for the parser to know which kind of object he faces until very late in the stream :
return (x) -> x.property;
// until the ">" character, the stream could be a valid statement like
"return (x)-1"; // the parser may need to restart analysis when he encounters the ">"
symbol // the situtation is worse when there's more than one parameter since the comma operator exists in ES5.
The @-syntax has the huge advantage of making the parser immediately confident of what kind of object he's going to parse.
I don't understand why nobody has taken this into consideration as of now.
Best , François
-----Message d'origine---
I would propose :
return ( fact@(n) ( n<=1 ? 1 : n*fact(n-1) ) );
Wouldn't that do the trick? I think that the @ char is not allowed in an identifier in ES5, which mean it would not introduce any compatibility issue.
-----Message d'origine---
On Jun 1, 2011, at 8:30 AM, Sean Eagan wrote:
Why not just move Arrow to the head to avoid any current or future ArrowFormalParameters parsing issues such as the GLR issue ?
There's no GLR issue if we do what we're doing for assignment expressions, including destructuring: parse a cover grammar into a reference-tree. I'm drafting that to see how it works in the existing spec.
Lots of languages and notations use arrow in between parameters and body. We should not deviate from that and uglify things lightly. I don't see good reason yet.
On Jun 1, 2011, at 9:17 AM, François REMY wrote:
It seems you're rethrowing the -> vs the @ syntax debate. (replace -> by @ in your proposal, you'll get the initial proposal I did)
@ is wanted for private names.
There's no need to go a bikeshed- or snipe-hunt for coveted, scarce single ASCII characters.
Last time I asked, it was the "#" char that was wanted for private names. If "#" has been replaced by "@" in private names, then we can replace "@" by "#" in my proposal, and return to the original proposal of #functions. If private name uses both @ and #, I raise severe concerns about it. Since special ASCII chars are scarce, as you said, it seems unappropriate to use two of them in a single module of Harmony, removing to all other modules (and future proposals) the possibility to use these symbols. Beside that, private names are great but not necessary.
BTW, you could use -> for private names. If I remember correctly my C
lessons, the -> operator is used to access members. You could use it for
private names, it would fit very nicely.
function setPrivateProperty(obj, value) {
private prop;
myObj->prop= value;
return private->prop;
}
var obj = {};
private prop = setPrivateProperty(obj, true);
obj.prop // undefined
obj->prop // true
, François
-----Message d'origine---
On Jun 1, 2011, at 10:38 AM, François REMY wrote:
Last time I asked, it was the "#" char that was wanted for private names. If "#" has been replaced by "@" in private names, then we can replace "@" by "#" in my proposal, and return to the original proposal of #functions.
is wanted for frozen/joined value types: joined functions with shorter syntax, records, tuples.
Hope this helps, it's not fun grabbing the last few easily-typed characters not used by JS. Quasis use ` now.
The punctuation soup argument is a bit general and overused against attribute modifiers for properties, IMHO, but it is a good countervailing force against lame single-character "land grabs" to try to shorten (some) syntax without thinking much about usability, semantics, future uses, or connotation in other languages.
If private name uses both @ and #, I raise severe concerns about it.
No one ever said any such thing.
Good point, the Identifier + ArrowFormalParameters would be ambiguous with a function call. That could be fixed though by just putting the Identifier before the Arrow:
higher( fact -> (n) n<=1 ? 1 : n * fact(n-1));
var warmer -> (a) {...};
let warm -> (b) {...};
const colder -> (c) {...};
const #coldest -> (d) {...};
On Wed, Jun 1, 2011 at 11:15 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
one thing that stands out in your proposal is that there doesn't appear to be any way to write a recursive arrow function.
Here is one way it might be done:
higher(->: fact (n) n<=1?1:n*fact(n-1));
or possibly
higher(->@ fact (n) n<=1?1:n*fact(n-1));
(in either case the 3 character arrow sequence would be one token)
Thanks, Sean Eagan
Ok, then I'm fine with it. Please note that the current strawman still make use of the # symbol, which is why I thought you were using both of them in a future proposal.
Anyway, what do you think of my “–>” proposal for private names?
I tend to like it, since it solves one of the concern many people made for private names (that it introduced a difference between o.prop and o["prop"], and that introducing a private name force you to check all your code since all property accesses are susceptible to be modified by the insertion of the private instruction before them). Using a specific instruction for private names solves this problem completely.
It also release a special char (#,@, or whatever char you wanted to use) for other uses, since private->name works pretty well and is very consistent with obj->property. I'm not sure that @.name is really the way to go for private names since we don't have many special chars left and there are good alternative ways to solve this problem. Even if we keep the current "." approach for private names, we could use "private.name" to get a private name handle.
As I already said, I don't find it natural to define functions by writing an arrow between the arguments and the method body. Even mathematicians don't do this in real life. Everybody use exp(x) = Σ(x^n/n!) and not exp(x) -> Σ(x^n/n!) while this is the official notation. Not to say it becomes really strange when you don't have arguments at all, like in setInterval(=>this.doAction(), 1000);
If we could use a # or a @ notation for short function notation, I would be very pleased, and my developers would be, too. If that was not possible, I would not defend this anymore, but I'm under the impression it's still time to manage to get this syntax instead of the arrow syntax. I'm really convinced that, if given the choice, the majority of JavaScript developers would go for a @(x) or #(x) syntax ahead of an arrow syntax notation. But maybe am I wrong.
-----Message d'origine---
On Jun 1, 2011, at 11:53 AM, François REMY wrote:
Ok, then I'm fine with it. Please note that the current strawman still make use of the # symbol, which is why I thought you were using both of them in a future proposal.
You must be reading an older strawman. The one promoted to Harmony last week is
and it adds no new syntax, just semantics with API.
Anyway, what do you think of my “–>” proposal for private names?
No one wants to use the C/C++ pointer to struct member operator for something quite different. OTOH @ is one char and (with a restricted production for the binary operator) can be used as a unary prefix operator for "this@" shorthand when accessing private instance variables in methods in a class.
It also release a special char (#,@, or whatever char you wanted to use) for other uses, since private->name works pretty well and is very consistent with obj->property. I'm not sure that @.name
That's not a going proposal, nor is #.name -- the whole "private x;" declaration form, which implies a new static binding chain for identifier uses on the right of dot in member expressions and left of colon in object initialisers, was a bit controversial (even though aspects of it resurface, e.g. in scoped object extensions).
Private name objects are in Harmony without syntax. But classes need syntax for method access to private instance variables. This is the big open issue to resolve quickly for classes to stay in Harmony.
Why not just move Arrow to the head to avoid any current or future ArrowFormalParameters parsing issues such as the GLR issue ?
ArrowFunctionExpression : Arrow ArrowFormalParametersOpt InitialValue Arrow ArrowFormalParametersOpt BlockOpt
This would deviate from C# and Coffeescript tradition, but I think even for people familiar with those languages it would be an easy transition. They could potentially be called "arrowhead" functions as a mnemonic device for the arrow position if necessary.
Here's what the examples from the arrow function syntax strawman [1] would then look like:
// Empty arrow function is minimal-length let empty = ->;
// Expression bodies needs no parentheses or braces let identity = -> (x) x;
// Fix: object initialiser need not be parenthesized, see Grammar Changes let key_maker = -> (val) {key: val};
// Nullary arrow function starts with arrow (cannot begin statement) let nullary = -> preamble + ': ' + body;
// No need for parens even for lower-precedence expression body let square = -> (x) x * x;
// Statement body needs braces, must use 'return' explicitly if not void let oddArray = []; array.forEach( -> (v, i) { if (i & 1) oddArray[i >>> 1] = v; });
// Use # to freeze and join to nearest relevant closure function return_pure() { return # -> (a) a * a; }
let p = return_pure(), q = return_pure(); assert(p === q);
function check_frozen(o) { try { o.x = "expando"; assert(! "reached"); } catch (e) { // e is something like "TypeError: o is not extensible" assert(e.name == "TypeError"); } }
check_frozen(p);
function partial_mul(a) { return # -> (b) a * b; }
let x = partial_mul(3), y = partial_mul(4), z = partial_mul(3);
assert(x !== y); assert(x !== z); assert(y !== z);
check_frozen(x); check_frozen(y); check_frozen(z);
// Use ''=>'' (fat arrow) for lexical ''this'', as in CoffeeScript // ("fat" is apt because this form costs more than ''->'')
const obj = { method: function () { return => this; } }; assert(obj.method()() === obj);
// And only lexical ''this'' for => functions
let fake = {steal: obj.method()}; assert(fake.steal() === obj);
// But ''function'' still has dynamic ''this'' let real = {borrow: obj.method}; assert(real.borrow()() === real);
// Recap: // use ''->'' instead of ''function'' for lighter syntax // use ''=>'' instead of calling bind or writing a closure
const obj2 = { method: -> () (=> this) }; assert(obj2.method()() === obj2);
let fake2 = {steal: obj2.method()}; assert(fake2.steal() === obj2);
let real2 = {borrow: obj2.method}; assert(real2.method()() === real2);
// An explicit ''this'' parameter can have an initializer // Semantics are as in the "parameter default values" Harmony proposal const self = {c: 0}; const self_bound = -> (this = self, a, b) { this.c = a * b; }; self_bound(2, 3); assert(self.c === 6);
const other = {c: "not set"}; self_bound.call(other, 4, 5); assert(other.c === "not set"); assert(self.c === 20);
// A special form based on the default operator proposal const self_default_bound = -> (this ??= self, a, b) { this.c = a * b; } self_default_bound(6, 7); assert(self.c === 42);
self_default_bound.call(other, 8, 9); assert(other.c === 72); assert(self.c === 42);
// ''=>'' is short for ''->'' with an explicit ''this'' parameter
function outer() { const bound = => () this; const bound2 = -> (this = this) this; // initializer has outer ''this'' in scope const unbound = -> () this; const unbound2 = -> (this) this;
return [bound, bound2, unbound, unbound2]; }
const t = {}, u = {};
const v = outer.call(t);
assert(v0 === t); assert(v1 === t); assert(v2 === t); assert(v3 === t);
assert(v[0].call(u) === t); assert(v[1].call(u) === t); assert(v[2].call(u) === u); assert(v[3].call(u) === u);
// Object intialiser shorthand: "method" = function-valued property with dynamic ''this'' const obj = { method -> () { return => this; } };
// Name binding forms hoist to body (var) or block (let, const) top var -> warmer(a) {...};
let -> warm(b) {...};
const -> colder(c) {...};
const # -> coldest(d) {...};
Also, why not allow the explicit this parameter with current function syntax as well via:
ArrowFunctionExpression : Arrow FormalParametersOpt InitialValue Arrow FormalParametersOpt BlockOpt
FunctionDeclaration : function Identifier FormalParameters { FunctionBody }
FunctionExpression : function IdentifierOpt FormalParameters { FunctionBody }
FormalParameters : ( FormalParameterListOpt )
FormalParameterList : ... this InitialiserOpt this InitialiserOpt , FormalParameterList
[1] strawman:arrow_function_syntax
Thanks, Sean Eagan