arrow syntax unnecessary and the idea that "function" is too long
Le 07/05/2011 02:04, Peter Michaux a écrit :
I'd like to ask when is "function" too long? I never type it thanks to my text editor's features so I know it is not too long for developers with a good editor.
What editor are you using? I have always been disappointed in my experience with IDEs and JavaScript integration and would be glad to know what people use for JavaScript (I'm actually asking the question to everyone).
I'm attracted to the idea of a shorter function syntax not only because it reduces the number of characters of the "function" keyword, but also because it gets rid of the "return" keyword (and corresponding semicolon). The particular case where I would enjoy shorter syntax is when using inlined functions in array extras.
// assuming a is an array a.filter( (e)->(typeof e === "number" && e>3) ) .map( (e)->(e*e) ) .reduce( (prev, curr)->(prev+curr), 0);
This is obviously extremely subjective, I admit. And there is no right or wrong answer/opinion, it's really a matter of taste. I actually prefer the idea of the # notation, because it looks "more" like a function with its brackets ("{" and "}") while in my example, without any help of syntax highlighting, the reader can easily get lost in nested parenthesis. Same example with #:
// assuming a is an array a.filter( #(e){typeof e === "number" && e>3} ) .map( #(e){e*e} ) .reduce( #(prev, curr){prev+curr}, 0);
This looks more clear to me. But once again, this is very subjective.
Your message seems to assume that the choice of providing a shorter syntax is to help JS code writer. I have the opposite opinion: a shorter syntax should be introduced to help code readers. In most cases I have seen for array extras functions, the function has only one return statement. While reading the code, having the function inlined avoids to look for the function in some other place in the code and getting rid of a dozen character makes the line shorter without introducing ambiguity.
My two cents,
On May 6, 2011, at 5:04 PM, Peter Michaux wrote:
The only possible category is "be a better language" but the arrow syntax won't make JavaScript a better language for complex applications or libraries in comparison to any other kind of JavaScript code.
Usability is always on the top three lists of programming language success factors. 'function' and 'return' are too long.
I would argue that the arrow syntax will make JavaScript a worse language anyway as there are already perfectly good forms using the "function" keyword now.
Eight characters is at least six too many.
We don't need new syntax and we don't need multiple ways to do the same thing just for the sake 6
Wrong, 14. You are not counting 'return'.
characters. Please keep JavaScript simple.
Sorry, this is a bogus argument. "Simple" does not mean "fewest productions in all possible grammars" or "fewest ways of saying any given sentence." That is simpler by some measures, more complex by others. In particular, writing and (lesser but still material) reading 'function' over and over is not a win.
Consider the destructuring object shorthand: let {x, y} = pt; instead of let {x:x, y:y} = pt;
Look at all the complex/subtle edge cases mentioned in the wiki page about arrow function syntax. Do we really want to have that much trickiness added to the language?
The wiki page is a work in progress. I have updates coming, which should address the parenthesization burden. But again, you can use 14 characters if you want. This is shorthand, and only shorthand. And usability counts, so shorthands are in Harmony (e.g., destructuring)
Gzip is not the issue (although stats I've seen from Steve Souders show too may scripts not being compressed at the Transfer-encoding layer). Human usability is.
On Fri, May 6, 2011 at 6:39 PM, Brendan Eich <brendan at mozilla.com> wrote:
But again, you can use 14 characters if you want.
The problem is that the author of the code that I'm reading may have used the arrow syntax and then I'm stuck reading it.
This is shorthand, and only shorthand. And usability counts, so shorthands are in Harmony (e.g., destructuring)
Yes and readability counts. JavaScript's function syntax is already highly usable and readable. Having many ways to write the same thing is a burden to readers of code because they have to know a larger set of forms and all of the gotchas that come along with them.
A lot of languages have a lot of "cool syntax" and then the communities come up with best practices that prohibit the use of them anyway often for reasons only discovered after their introduction. My hunch is that arrow syntax will be one of these cases.
JavaScript can use attention in many of areas. Devoting time to adding sugary function syntax seems like a misappropriation of resources.
Peter
On May 7, 2011, at 12:42 AM, Peter Michaux wrote:
Yes and readability counts. JavaScript's function syntax is already highly usable and readable.
Many people, including me, would disagree. On matters of taste, I'd want the committee to listen to all interested parties and try to pick the solution that pleases the most people. That appears to be what's happening here.
On Fri, May 6, 2011 at 10:49 PM, Andrew Dupont <mozilla at andrewdupont.net> wrote:
On May 7, 2011, at 12:42 AM, Peter Michaux wrote:
Yes and readability counts. JavaScript's function syntax is already highly usable and readable.
Many people, including me, would disagree.
Do you really struggle using or reading the current function syntax?
Peter
Many people, including me, would disagree. On matters of taste, I'd want the committee to listen to all interested parties and try to pick the solution that pleases the most people. That appears to be what's happening here.
Based on what evidence are "we" concluding that the majority of the javascript developers want -> syntax for functions? The fact that
coffeescript is the hot buzzword? Was there some developer-community wide voting or poll that I missed? Or is it that a few vocal people on these lists like it, and that's being substituted as what the "majority" is in favor of?
I'm not just being snarky, I'm genuinely curious, on this and a variety of other matters related to what's being added to ES-next/harmony... It's clear Brendan (and other language cohorts) likes these new syntax sugars, but where is the evidence that suggests that all this new syntax sugar is the exact sugar that javascript developers want? Is it just enough that everyone at JSConf likes it, and thus that means that the whole community is assumed to be on board?
There's LOTS of examples where writing less JavaScript is more awesomer, but there's also plenty of examples of where writing less is much more uglier. I am troubled by the implication that just because we've found a shorter syntax sugar for functions, this unequivocally means it's better.
-> syntax being shorter is a clear and objective question. No doubt it's
shorter. But is is prettier or more readable? According to who's opinion do we conclude that, because that seems pretty subjective.
On Fri, May 6, 2011 at 11:05 PM, Andrew Dupont <mozilla at andrewdupont.net> wrote:
I don't want to get too deep into matters of taste, but I do think the current syntax is annoyingly verbose for passing lambdas as arguments in other functions. The fact that it's so verbose ends up hurting readability when the function itself is short.
I think that this is what compilers and projects like coffeescript are for. In my opinion, JavaScript itself doesn't need this new syntax.
I think improving JavaScript as a compilation target is a good goal. For example, a real "lambda" with guaranteed proper tail calls, no "arguments", no need for "return", etc would make is possible to compile Scheme to JavaScript without using something inefficient like trampolines. It would also open up recursive programming options in plain JavaScript so it would be win-win.
Peter
On 07/05/2011, at 02:04, Peter Michaux wrote:
(...)
If the arrow syntax is only syntactic sugar for the existing function forms then I don't see how it achieves any of the goals he outlined. The only possible category is "be a better language" but the arrow syntax won't make JavaScript a better language for complex applications or libraries in comparison to any other kind of JavaScript code. I would argue that the arrow syntax will make JavaScript a worse language anyway as there are already perfectly good forms using the "function" keyword now. We don't need new syntax and we don't need multiple ways to do the same thing just for the sake 6 characters. Please keep JavaScript simple.
(...)
This above is ~ how I feel about it too.
But if I wanted a shorter syntax, I would no doubt choose ruby blocks' syntax, it's even shorter yet and it's familiar already to millions of programmers.
On 07/05/2011, at 03:22, David Bruant wrote:
I'm attracted to the idea of a shorter function syntax not only because it reduces the number of characters of the "function" keyword, but also because it gets rid of the "return" keyword (and corresponding semicolon).
(return does not need the semicolon ;-)
The particular case where I would enjoy shorter syntax is when using inlined functions in array extras.
// assuming a is an array a.filter( (e)->(typeof e === "number" && e>3) ) .map( (e)->(e*e) ) .reduce( (prev, curr)->(prev+curr), 0);
Using ruby blocks' syntax (+6 versus +4 chars):
a.filter( {|e| typeof e === "number" && e>3}) .map( {|e| e*e } ) .reduce( {|prev, curr| prev+curr}, 0);
Is "{|" as a token likely to be found in any .js source file in the world, as of today ?
- Not in any object literal
- Not likely to be found at the beginning of a block.
- Inside a string it would not matter.
Just to add my two cents, I would like to let you remember that the arrow syntax should not be viewn as the only way to avoid the 'return' statement and the brackets. "function(x) xx;" does the trick too, whithout introducing any new keyword. To those that think that the arrow syntax is easier to type because there's less characters to type, it may be disappointing to notice it's not the case : "(x) -> xx;" is only 5
characters shorter than the other form but :
- You don't beneficiate from autocompletion anymore (in most IDE, typing
'fun+TAB' brings up 'function' arlready)
- The '-' and the '>' characters are more complex to type (on my
keyboard, both then - and the > char requires me to move my hand away from
its standards position, and the time it takes to type ' -> ' equals or is
more important than the time I need to type 'function' in full word, which I usually don't need to).
- The syntax is less clear. CSharp originally introduced something like
that in the past, and I never liked the syntax. (It's to notice that the VB.NET language later implemented the lambda feature using the "Function(X) XX" syntax). Okay, if I could really choose, I would prefer the "@(x) xx;" syntax, which is already implemented "as-is" in other scripting languages such as MatLAB (but I already hear the concerns about other possible usages of the @ sign).
- It introduces ambiguities in the code (Sample: var z = (x) -> x || y)
, François
-----Message d'origine---
On Sat, May 7, 2011 at 2:22 AM, Peter Michaux <petermichaux at gmail.com> wrote:
I think that this is what compilers and projects like coffeescript are for. In my opinion, JavaScript itself doesn't need this new syntax.
I think improving JavaScript as a compilation target is a good goal.
This argument comes up time and again: "We don't need to make JavaScript a good programming language, just a good compilation target". I think it's really wrong-headed. First, JavaScript is a language used by millions of people as a programming language, and we should give them a great language to program in. Second, JavaScript as source rather than target has been a huge enabler of the Web as an open platform, which I certainly don't want to move away from. So, even though we've worked hard in the module system to better support compilation to JavaScript, I think the our fundamental goal should be to make JavaScript a great language to write all kinds of programs in.
For example, a real "lambda" with guaranteed proper tail calls, no "arguments", no need for "return", etc would make is possible to compile Scheme to JavaScript without using something inefficient like trampolines. It would also open up recursive programming options in plain JavaScript so it would be win-win.
And hey, it turns out we've done this too -- at least with the -> syntax. :)
On Sat, May 7, 2011 at 6:04 AM, Sam Tobin-Hochstadt <samth at ccs.neu.edu> wrote:
On Sat, May 7, 2011 at 2:22 AM, Peter Michaux <petermichaux at gmail.com> wrote:
I think that this is what compilers and projects like coffeescript are for. In my opinion, JavaScript itself doesn't need this new syntax.
I think improving JavaScript as a compilation target is a good goal.
This argument comes up time and again: "We don't need to make JavaScript a good programming language,
JavaScript is already a good programming language. It can use improvements but it has "good" covered.
just a good compilation target".
I did not write that it needs to be "just a good compilation target."
I don't use a compiler to enable me to write source in another language and then serve JavaScript to the browser. I write in JavaScript. So I do want JavaScript to remain a good language.
That said, improving JavaScript as a compilation target does expose areas where the language could use features it does not have at all (in any syntax.) Adding those features makes JavaScript objectively a more capable language.
I think it's really wrong-headed.
Me too.
First, JavaScript is a language used by millions of people as a programming language, and we should give them a great language to program in.
JavaScript already has "great" covered too. :-) I'd be willing to go for "even better" but the arrow syntax isn't even a significant contribution to this cause. Real features would be. A weak map, for example, is a great idea because we just cannot do anything like that now without implementing our own garbage collection.
Second, JavaScript as source rather than target has been a huge enabler of the Web as an open platform, which I certainly don't want to move away from. So, even though we've worked hard in the module system to better support compilation to JavaScript, I think the our fundamental goal should be to make JavaScript a great language to write all kinds of programs in.
That wasn't one of Brendan's stated goals; however, it is a good goal. I think the arrow syntax is not helpful in this goal.
For example, a real "lambda" with guaranteed proper tail calls, no "arguments", no need for "return", etc would make is possible to compile Scheme to JavaScript without using something inefficient like trampolines. It would also open up recursive programming options in plain JavaScript so it would be win-win.
And hey, it turns out we've done this too -- at least with the -> syntax. :)
It has been confirmed that the arrow syntax is only syntactic sugar for existing function syntax. That means introducing the arrow syntax does not improve the compilation Scheme to JavaScript at all.
Peter
On Sat, May 7, 2011 at 6:31 PM, Peter Michaux <petermichaux at gmail.com> wrote:
On Sat, May 7, 2011 at 9:16 AM, Thaddee Tyl <thaddee.tyl at gmail.com> wrote:
I believe that David Bruant has a good point. We need a shorter syntax because we advocate the use of map/reduce, etc., which require simple anonymous functions.
No. We don't "need" syntactic sugar. The current function syntax is working and we are talking a few characters difference, not hundreds.
Map/reduce don't "require" syntactic sugar.
It is not a requirement, indeed. I feel like it is a need, however. JavaScript is still seen as a badly object-oriented programming language by those who still think it is java with a weird syntax. I do hope it grows to be known as an outstanding functional programming language. Thanks to ES5's strict mode, it now gets freed from the "this" issue, for those that use it.
Huffmanization requires that we reduce the size of what we want to use often. If we want to use more functions, then it isn't just eleven less characters once in a while, it becomes a bigger deal!
There are so many more important issues to address.
If you feel like addressing more important issues, I warmly beg you to do so!
On Sat, May 7, 2011 at 9:56 AM, Thaddee Tyl <thaddee.tyl at gmail.com> wrote:
JavaScript is still seen as a badly object-oriented programming language by those who still think it is java with a weird syntax.
I think that concpetion has declined a lot as rich clients have forced people to become better acquainted with JavaScript and a lot more has been written on the language.
I do hope it grows to be known as an outstanding functional programming language.
JavaScript won't ever be known as a outstanding functional programming language until it has proper tail calls. This would give the language new capabilities it doesn't have now.
Peter
For what it's worth, I'm a huge fan of Ruby's {|-style blocks. Also, it's worth noting that "do...done" seems to be a bit more popular in Ruby programs that I've seen.
I'm not a fan of the fact that these blocks have different behavior than "regular" functions and methods, but that's a qualm for a different mailing list, and I'm not a rubyist anyhow :)
Consider this: w = (x)->y || z
That code is not obvious at all. Which of these would it be?
1: w = function (x) { return y } || z 2: w = function (x) { return y || z }
It seems to me that there must be some sort of delineation around the function start and end. I agree that "function ... return" is way too many characters to write and read for such a fundamental bit of syntax.
This style is quite clear and readable:
w = {|x| y || z} w = {|x| y} || z
However, that's pretty awful to type. Perhaps even worse than ->.
Maybe {(x) y || z} might be better? Of course, that would break blocks that start with parenthesized sequence blocks, but is that really a concern? Blocks in JS are useless, can't we just do away with them?
On 5/7/11, Isaac Schlueter <i at izs.me> wrote:
[...]
Blocks in JS are useless, can't we just do away
with them?
Blocks are required for many productions such as try/catch/finally. Almost all existing code uses blocks to group statements together. Blocks can't be removed.
On Sat, May 7, 2011 at 1:04 PM, Peter Michaux <petermichaux at gmail.com> wrote:
JavaScript won't ever be known as a outstanding functional programming language until it has proper tail calls. This would give the language new capabilities it doesn't have now.
harmony:proper_tail_calls (note that it's in the Harmony namespace, meaning that it's been approved as a proposal).
Consider this: w = (x)->y || z
That code is not obvious at all. Which of these would it be?
1: w = function (x) { return y } || z 2: w = function (x) { return y || z }
It seems to me that there must be some sort of delineation around the function start and end.
But such delineation does not have to lead to required syntax in the function construct. Such required delineations were not part of lambda-calculus originally **, they arose out of implementation limitations that can be overcome.
I know that takes some getting used to (been there myself*), but there is an established standard, both in publications on programming language theory, and in some real languages:
function bodies extend as far as possible **
So your examples would be
1: w = (function (x) return y) || z 2: w = (function (x) return y || z)
If the right-hand side itself is delimited, 2 could also be written
2': w = function (x) return y || z
The idea is that we can always "shorten" an unbounded function by enclosing it with existing grouping constructs, but we cannot "lengthen" a pre-delineated function in any way, nor can we get rid of the delineating parens and braces if they are required in the grammar. Combining non-delineated functions with grouping constructs gives us a modular and unambiguous solution.
Another issue is that of blocks in function bodies. It would be nice if blocks were values - then procedures would just be block-returning functions, and all functions would just return values, separating the function construct from the details of block execution. Not sure whether such niceties would work in javascript, though:-)
Claus
- I used to write my lambda-calculus terms fully parenthesized, because the functional languages I knew (before Haskell) required that style. Many programming language theory folks found that style difficult to read, because they had grown up with the extends-as-far-as-possible convention.
** Church, Barendregt, .., they all define lambda-terms as
term := x | (\x term) | (term term)
with additional conventions to drop parentheses where
possible, such as
(A B C D) instead of (((A B) C) D)
(\x y z.M) instead of (\x (\y (\z M)))
JavaScript won't ever be known as a outstanding functional programming language until it has proper tail calls. This would give the language new capabilities it doesn't have now.
Proper tail calls are already in Harmony and totally orthogonal to the question of new function syntax.
Based on what evidence are "we" concluding that the majority of the javascript developers want -> syntax for functions? The fact that coffeescript is the hot buzzword? Was there some developer-community wide voting or poll that I missed? Or is it that a few vocal people on these lists like it, and that's being substituted as what the "majority" is in favor of?
IIRC there were cheers at JSConf this week.
But you're looking for something that doesn't exist: a way to make scientifically sound decisions about language design. There is no way to resolve syntax questions perfectly. We welcome community input, all community input. But we are going to have to make a decision, and it simply won't be perfect. We're going to listen to everyone, consider the technical issues, and at the end of the day, make the best decision we can with imperfect information.
Based on what evidence are "we" concluding that the majority of the javascript developers want -> syntax for functions? The fact that coffeescript is the hot buzzword? Was there some developer-community wide voting or poll that I missed? Or is it that a few vocal people on these lists like it, and that's being substituted as what the "majority" is in favor of?
IIRC there were cheers at JSConf this week.
Yeah, I unfortunately wasn't able to attend. I was quite sad about missing JSConf for the first time.
But, JSConf has just 150-200 JavaScript developers in attendance. While they are certainly some of the most passionate (and intelligent) developers of the community, no doubt, they are definitely not a representative sampling of the overall community. Making language decisions based on the vocal support of JSConf alone is not sufficient. I was certain there had to be more behind the claim than just that. So that's what I was asking for.
But you're looking for something that doesn't exist: a way to make scientifically sound decisions about language design.
I am not looking for any such thing. I was looking for more detail behind Brendan's (and Andrew's) assertions that -> is definitively better because
it's shorter (and for no other stated reason).
There is no way to resolve syntax questions perfectly. We welcome community input, all community input.
I don't claim that any such perfect system could be devised. I was merely responding to Andrew's insinuation that the majority of the community (including him) had already voiced support for ->. If someone makes an
implication, I think it's fair game on here to ask for the supporting reasoning.
I think I could easily come up with a dozen examples of patterns in JavaScript coding which are shorter, but which "most of the community" would say is not more readable. So I take issue with the assertion that shorter==better unequivocally.
But we are going to have to make a decision, and it simply won't be perfect. We're going to listen to everyone, consider the technical issues, and at the end of the day, make the best decision we can with imperfect information.
From the tone of this thread, and from many other recent postings regarding
reactions from JSConf this week, it sounded like all of a sudden we'd gone from "yeah coffeescript has some interesting short-hand syntax" to "the community has spoken, and coffeescript will be adopted into ES.Harmony/Next as-is".
I was, and am now, still wondering how "we" so quickly made the leap from Brendan's "harmony of my dreams" a couple of months ago, where the idea of # sounded good, and plausible for inclusion, all the way to Brendan declaring that it's basically a done deal that we'll be including a variety of function and other shorthands from coffeescript post haste?
But, JSConf has just 150-200 JavaScript developers in attendance.
Right. The JS community has no borders, no government, no constitution, no membership cards, no census... We welcome everyone. So we have no way of instituting democratic institutions.
they are definitely not a representative sampling of the overall community. Making language decisions based on the vocal support of JSConf alone is not sufficient.
I can only repeat what I said before. There's no magic way to figure out accurately what most people want. The best we can do is publicize, solicit feedback, discuss, and make a decision. As we have always done.
I was merely responding to Andrew's insinuation that the majority of the community (including him) had already voiced support for ->.
You have no way of knowing Andrew was insinuating that. I saw only the eminently reasonable point that we will never be able to please everyone, and will have to try to please as many people as possible.
I take issue with the assertion that shorter==better unequivocally.
I don't know whether anyone actually made that assertion. But in the case of function literals, there is a ton of precedent for languages with very concise syntax, and lots of experience to show that the conciseness is a win here.
From the tone of this thread, and from many other recent postings regarding reactions from JSConf this week, it sounded like all of a sudden we'd gone from "yeah coffeescript has some interesting short-hand syntax" to "the community has spoken, and coffeescript will be adopted into ES.Harmony/Next as-is".
Hey, take a deep breath.
-
If you read the draft strawman, you'll see it's not exactly the same as the CoffeeScript syntax.
-
Brendan has been describing a strawman he is proposing at the next face-to-face meeting.
-
The strawman has not yet been promoted to Harmony status.
-
We always go to great pains to make it clear that nothing is final until the standard has been approved, which is slated for 2013. So even if it were at "Harmony status," it wouldn't be final.
You're reading into perceived "tone" and "insinuation" (your words) things that are directly contradicted by verifiable facts. Syntax discussions are difficult and controversial. If you want to contribute productively, please assume good faith on the part of your interlocutors. I think you'll find the assumption holds up.
Since there's a call for developer feedback, I'll give mine.
Brendan once said "JS is a curly-brace language and it always will be". I think the -> looks works very nice with a pythonic-like forced indentation
like Coffeescript has. However, I believe # looks better with curly braces, so I'd keep #(x) { x * x }.
I also think familiarity should be considered and that #(x) { x * x } would be more familiar to the casual JS programmer.
Juan
David,
Thanks for those clarifying points, much appreciated.
From an academic perspective, I'm also curious about the change from # to ->
To be honest, # always seemed weird to me, but I welcome a shortened syntax regardless
Rick
-- Sent from my Palm Pre On May 7, 2011 8:18 PM, Juan Ignacio Dopazo <dopazo.juan at gmail.com> wrote:
Since there's a call for developer feedback, I'll give mine. Brendan once said "JS is a curly-brace language and it always will be". I think the -> looks works very nice with a pythonic-like forced indentation like Coffeescript has. However, I believe # looks better with curly braces, so I'd keep #(x) { x * x }.
I also think familiarity should be considered and that #(x) { x * x } would be more familiar to the casual JS programmer. Juan
It has been my experience that professional JavaScripters will cheer any idea that shortens the spelling of "function" and "return" :)
Brendan has said that 8 characters for "function" is at least 6 too many. I think it's probably at least 7 too many. But it'd be a shame to remove the character-count-tax only to introduce a twisting-wrist-tax. I'd prefer something closer to the middle of (most) keyboards than -> or {|. #() is pretty nice, actually.
When I suggested "doing away with blocks", I of course was not referring to structures where the block is relevant, such a function bodies, if/else, try/catch/finally, or loops. I was talking about having a bare unadorned block in JavaScript. These are relevant in C, where you have block-scope, but in JavaScript have only made it trickier to know whether something is supposed to be an Object-literal or a block with labelled lines. For example:
return { foo: "bar" } // vs return { foo: "bar" }
On Sat, May 7, 2011 at 14:39, Claus Reinke <claus.reinke at talk21.com> wrote:
function bodies extend as far as possible **
I see. So, a function body would be just like an if-block or loop body. One full statement, or a block. There is precedent for that in the rest of the language. So, then, this case:
x = function () y; z
would be:
x = function () { return y }; z
am I understanding that correctly?
But, JSConf has just 150-200 JavaScript developers in attendance.
Right. The JS community has no borders, no government, no constitution, no membership cards, no census... We welcome everyone. So we have no way of instituting democratic institutions.
they are definitely not a representative sampling of the overall community. Making language decisions based on the vocal support of JSConf alone is not sufficient.
I can only repeat what I said before. There's no magic way to figure out accurately what most people want. The best we can do is publicize, solicit feedback, discuss, and make a decision. As we have always done.
OK, it's fair to point out that an attempt is being made. I'm asking though for the resulting evidence from that attempt. As far as I can tell (and please correct me if I'm wrong), there's been a few discussions on some rather-esoteric lists/threads, like es-discuss, a few strawmans, and some ad hoc presentations as JSConf. If there's a signficant medium of exchange of opinions and ideas about topics that I'm NOT listing there, please do tell me. I like to think I keep on the pulse of the JS community (generally speaking), and so I'm anxious to hear if and how I'm missing out.
If OTOH those few mediums do constitute the breadth of "community opinion solicitation" thus far regarding specifically the matters of these coffeescript shorthands, as I was previously inclined to believe, then my original assertion stands, that this doesn't constitute, in my opinion, enough of the broader perspectives on what is and is not useful and readable JavaScript. With all due respect, Brendan's personal tastes on what kind of code he likes to write is not enough. It has to be something that is likely to find wide spread support among the JavaScript masses.
And if we're looking for any kind of guide as to what they might like (because we cannot scientifically poll all of them, obviously), then might I suggest that the community that's grown up around jQuery (and its associated projects, plugin ecosystem, etc) is a place to start. I am not in any way suggesting jQuery is the only style of code out there, by any means. But it clearly represents a wide swath of how JavaScript developers are currently using the language. And jQuery is unique enough in its syntactic eccentricities (its chaining, etc) that it may offer some insights.
To the extent that jQuery syntax encourages people to take shortcuts, it could be seen as support for shorter syntax. And to the extent that jQuery uses lots of anonymous functions, it could be seen as an opportunity to shorten all that "function" soup.
But, by the same token, jQuery preserves verbosity in some places for
readability sake. For instance, event names are known by their full
canonical names, rather than by some shorthand (similarly with attribute and
property names). I can say as many times as I write click(...)
or
bind("click"...)
, I could see where c
or clk
might be nice to have, to
save on all that typing. But, it would probably be for a loss of readability
and semantics of the code.
So there has to be a careful balance struck between shortness and
readability. I think at least a few of us are saying that we're skeptical
that -> is sufficiently readable and semantic, compared to function(){} or
#(){}. The same goes for the loss of return
... Having return
in there is
a good thing, I think, because it makes it clear what's being returned. I
often write complex functions with internal branching logic, where there's
more than one return
statement, and so it scares me to think how I could
inspect and understand such code as readily/easily if the return
was
implicit, for instance, only the last evaluated expression, etc.
I was merely responding to Andrew's insinuation that the majority of the community (including him) had already voiced support for ->.
You have no way of knowing Andrew was insinuating that. I saw only the eminently reasonable point that we will never be able to please everyone, and will have to try to please as many people as possible.
Andrew's original message (in part):
I'd want the committee to listen to all interested parties and try to pick the solution that pleases the most people. That appears to be what's happening here.
The phrase "That appears to be what's happening here", following after the "committee...listen...pick" sentence before, led me to believe that Andrew was indicating that the movement to adopt Coffeescript-like shorthand was a result of the committee having already listened and having already picked a solution that most people agreed with. It was the implication of "this has already been happening" I reacted to. If I misread it, I apologize. But my interpretation was fueled strongly by half a dozen blog posts and dozens of tweets from JSConf and post-JSConf which seemed to suggest that this stuff was already basically a done-deal.
I take issue with the assertion that shorter==better unequivocally.
I don't know whether anyone actually made that assertion.
From Brendan earlier in the thread: This is shorthand, and only shorthand. And usability counts, so shorthands are in Harmony (e.g., destructuring)
I interpreted that as a pretty definitive "this is a done deal" type of statement, similar to the tone I interpreted from Andrew's statement, as described above. Again, if I read too far, I apologize, but these are exactly the phrases and interpretations which causes me to jump into this thread.
You're reading into perceived "tone" and "insinuation" (your words) things that are directly contradicted by verifiable facts.
I apologize if that's the case. But it sure sounded like it was a decided issue (more or less) that Coffeescript shorthands, or something like it, would be showing up in a browser near me pretty quickly. I understand that Brendan can make such changes in Firefox (I am a Mozilla employee) rather quickly ahead of final spec standardizations, and this is probably what he's planning (or already) done.
But optimistically putting in a set of shorthands (which some forward-thinking devs will immediately start writing against -- especially mozilla employees working on Firefox itself) so far in advance of when it's really had a chance to settle out in the community and let the community "vote" (by virtue of use or non-use) on various syntax changes... that carries with it some risk of the tail-wagging-the-dog effect.
So I felt like it was important to voice "early" that not everyone feels universally so lovey-dovey over that syntax. In fact, a recent tweet I read sums up my feelings: "If I wanted to be using Coffeescript, I'd be using Coffeescript. I prefer JavaScript."
If you want to contribute productively, please assume good faith on the part of your interlocutors. I think you'll find the assumption holds up.
I don't think this is a situation of not assuming good faith. If I thought this list acted in bad faith, I wouldn't waste my time here.
I think it's a question of reading (perhaps too far) in between the lines to interpolate that a larger (and more fast moving) trend was occurring than seemed to be being explicitly disclosed. Again, given all the buzz that came out this week after JSConf, to then see this thread and some phrases which were suggestive of "it's a done deal", I wondered to myself if there'd been some sort of community defining moment at JSConf that I (and millions of other devs) had just missed the boat on.
I apologize for my overreactions. And I renew my call that there should be more direct solicitation of feedback from the greater community, rather than taking what the few of us here on these lists have to say as sufficient.
"Kyle Simpson" <getify at gmail.com> Date: Sat, 7 May 2011 21:58:32 -0500 Subject: Re: arrow syntax unnecessary and the idea that "function" is too long
<snip>
With all due respect, Brendan's personal tastes on what kind of code he likes to write is not enough. It has to be something that is likely to find wide spread support among the JavaScript masses.
Since the arrow syntax assailants have been quite vocal on this list, lest they be construed as representative of the javascript masses, I would like to voice a strong endorsement for pursuing and exploring the arrow syntax further - and I do this as a simple javascript hobbyist who uses javascript (and JQuery, for lack of the perfect library) extensively to automate tasks on windows (via htas) and to write RIAs.
With all due respect to Mr. Simpson's personal tastes, I find the aesthetics of the arrow-syntax far more consistent with javascript's C-based-syntactic roots than the preprocessor-tainted '#' - but I also recognize that my personal aesthetic tastes are just that. Anyway, I hope that enough general users share my aesthetic and usability preference (short syntax for functionally well behaved and intuitive lambdas with closure capability) that the arrow syntax is given some serious thought and not dismissed because of this thread.
Thanks!
Faisal Vali
I wrote PHP full time for years. -> can get pretty aggravating. # is
50% shorter, and doesn't use the same fingers that type the (). ()->
is a lot of right-hand-dancing.
That being said, it does look pretty nice, and we're all just going to set our editors to do that for us anyhow, right?
On 5/7/11, Faisal Vali <faisalv at gmail.com> wrote:
"Kyle Simpson" <getify at gmail.com> Date: Sat, 7 May 2011 21:58:32 -0500 Subject: Re: arrow syntax unnecessary and the idea that "function" is too long
<snip>
With all due respect, Brendan's personal tastes on what kind of code he likes to write is not enough. It has to be something that is likely to find wide spread support among the JavaScript masses.
Since the arrow syntax assailants have been quite vocal on this list,
Yeah, not much vocal "whatevers", right?
I haven't seen much into the benefit of ->. I haven't given it a whole
lot of thought and don't find it all that thrilling, really. Unusually underopinionated for me, I know. Though If I was forced to pick between -> and #, I'd pick #.
On 08/05/2011, at 05:52, Faisal Vali wrote:
(...) I find the aesthetics of the arrow-syntax far more consistent with javascript's C-based-syntactic roots than the preprocessor-tainted '#' (...)
Consistent ?
-> in C has a totally different meaning !
On 08/05/2011, at 04:58, Kyle Simpson wrote:
(...) So I felt like it was important to voice "early" that not everyone feels universally so lovey-dovey over that syntax. (..)
What happened to "Allen's lambda syntax proposal" ? When, why was it ditched in favor of -> ?
Brendan, you liked it. What has happened ?
On Sun, May 8, 2011 at 4:04 AM, Jorge <jorge at jorgechamorro.com> wrote:
On 08/05/2011, at 05:52, Faisal Vali wrote:
(...) I find the aesthetics of the arrow-syntax far more consistent with javascript's C-based-syntactic roots than the preprocessor-tainted '#' (...)
Consistent ?
-> in C has a totally different meaning !
Yes, but that is why I alluded to a syntactic commonality and not a semantic one. But, I can see how the disparity in semantics might bother some programmers.
Just read esdiscuss/2008-November/008218 and I'm buzzing with the idea of Lisp style functions as "inspiration" for a short hand. While I realize the idea is likely absurd, but I'm thinking in terms of concepts that all JavaScript devs know and understand.
This is a super simple, first-pass, rough-draft, not-too-serious, request-for-comments...
On Sat, May 7, 2011 at 4:17 PM, David Herman <dherman at mozilla.com> wrote:
But we are going to have to make a decision, and it simply won't be perfect. We're going to listen to everyone, consider the technical issues, and at the end of the day, make the best decision we can with imperfect information.
I hope the committee keeps in mind that it can choose not to include any short function syntax. I know the committee knows that but I hope it is near the top of the list as one of the options.
On Sat, May 7, 2011 at 4:40 PM, Kyle Simpson <getify at gmail.com> wrote:
But, JSConf has just 150-200 JavaScript developers in attendance. While they are certainly some of the most passionate (and intelligent) developers of the community, no doubt, they are definitely not a representative sampling of the overall community. Making language decisions based on the vocal support of JSConf alone is not sufficient.
Agreed. I think the personality type of hundreds of developers that attend conferences is quite different than the tens of thousands of developers that don't attend.
I think I could easily come up with a dozen examples of patterns in JavaScript coding which are shorter, but which "most of the community" would say is not more readable. So I take issue with the assertion that shorter==better unequivocally.
Agreed. There shouldn't be the feeling that shorter function syntax is desperately needed and that it has to go into the next ES even if it is not perfect.
On Sat, May 7, 2011 at 5:18 PM, Juan Ignacio Dopazo <dopazo.juan at gmail.com> wrote:
Brendan once said "JS is a curly-brace language and it always will be". I think the -> looks works very nice with a pythonic-like forced indentation like Coffeescript has. However, I believe # looks better with curly braces, so I'd keep #(x) { x * x }. I also think familiarity should be considered and that #(x) { x * x } would be more familiar to the casual JS programmer.
I agree with this type of thinking about keeping syntax similar with arguments in parens and the body in braces more than introducing something so foreign to JavaScript like the arrow syntax.
On Sat, May 7, 2011 at 7:33 PM, Isaac Schlueter <i at izs.me> wrote:
It has been my experience that professional JavaScripters will cheer any idea that shortens the spelling of "function" and "return" :)
There are professional JavaScript programmers in this thread that aren't cheering. That is why this thread started.
On Sat, May 7, 2011 at 7:58 PM, Kyle Simpson <getify at gmail.com> wrote:
So I felt like it was important to voice "early" that not everyone feels universally so lovey-dovey over that syntax. In fact, a recent tweet I read sums up my feelings: "If I wanted to be using Coffeescript, I'd be using Coffeescript. I prefer JavaScript."
Exactly! There are syntactic features that some developers want that are so far from JavaScript that they shouldn't or can't be incorporated into the language. This is why compilers exist and I hope that the to-JavaScript compiler community grows if people want to do that sort of thing.
I've talked with some JavaScript developers and asked them "What do you think of Coffeescript?" without biasing my question. I've had a 100% negative response. They aren't interested in using Coffeescript at_all. So just because Coffeescript has some vocal fans, it has not caught on like wildfire. In the big scheme of things it has virtually not caught on at all. It is a very fringe group that is experimenting.
Peter
I'm really happy that arrow syntax proposal was made and thanks a lot Brendan!!
I'd like to point out that coffeescript has a huge success and in the end it's just syntax sugared js. I think this is quite good proof that syntax change like this is more then welcome.
Another thing I'd like to point out that arrow function is not just saving keystrokes of typing function
and return
, but also gives even bigger win IMO via =>
when binding of this
pseudo variable is desired. This case BTW was not addressed by #
. Even though ->
is one more char in comparison to #
, =>
is much less then .bind(this)
, in addition having both -> and => feels just natural!
-- Irakli Gozalishvili Web: www.jeditoolkit.com Address: 29 Rue Saint-Georges, 75009 Paris, France
On Sun, May 8, 2011 at 11:34 AM, Irakli Gozalishvili <rfobic at gmail.com> wrote:
I'd like to point out that coffeescript has a huge success and in the end it's just syntax sugared js.
Can someone give evidence that Coffeescript is actually a success? Has anyone crawled the web to determine the rate of Coffeescript adoption? (Assuming there is some way to identify Coffeescript's compiled code.) Will adoption plateau at a small percentage of total browser scripts?
People cannot just reiterate this idea that Coffeescript is popular and use that as support for arrows without evidence that Coffeescript is actually popular.
Peter
On May 8, 2011 8:34 PM, "Irakli Gozalishvili" <rfobic at gmail.com> wrote:
I'm really happy that arrow syntax proposal was made and thanks a lot
Brendan!!
I'd like to point out that coffeescript has a huge success and in the end
it's just syntax sugared js. I think this is quite good proof that syntax change like this is more then welcome.
To me the success of coffeescript is that it shows that those who want to do experiments with JS syntax don't have to burden the web platform with their language extensions in all perpetuity. Those who want the new syntax can have it now without waiting 5 years for IE10 to die. And if CoffeeScript turns out to be a terrible mistake then everyone who cares can stop using it and, poof, it's gone, unlike proto, with, eval scope modification, == etc.
Saying that CoffeeScript shows we should be making fundamental changes to JS syntax feels to me like arguing that the success of JRuby shows Java should look like Ruby.
Having a C-like syntax is IMHO a strength for JS. We could add a shorter version of 'function', and in 5 year's time we can even start using it on the web. But messing fundamentally with the syntax risks ending with something that is very hard to parse by programmers used to C-like languages. It's not like we can remove the old syntax so every new piece of syntax is additional in terms if what has to be grokked by every programmer, IDE, syntax highlighter, verifier and VM.
Personally, I'd like to argue against the idea that JS is a good place to experiment with language design. I think JS is far too important and hard to iterate for that.
Another thing I'd like to point out that arrow function is not just saving
keystrokes of typing function
and return
, but also gives even bigger win
IMO via =>
when binding of this
pseudo variable is desired. This case
BTW was not addressed by #
. Even though ->
is one more char in
comparison to #
, =>
is much less then .bind(this)
, in addition having
both -> and => feels just natural!
-- Irakli Gozalishvili Web: www.jeditoolkit.com Address: 29 Rue Saint-Georges, 75009 Paris, France
On Sunday, 2011-05-08 at 19:09 , Rick Waldron wrote:
Just read
esdiscuss/2008-November/008218 and I'm buzzing with the idea of Lisp style functions as "inspiration" for a short hand. While I realize the idea is likely absurd, but I'm thinking in terms of concepts that all JavaScript devs know and understand.
This is a super simple, first-pass, rough-draft, not-too-serious,
request-for-comments...
Rick
On Sun, May 8, 2011 at 1:51 PM, Faisal Vali <faisalv at gmail.com> wrote:
On Sun, May 8, 2011 at 4:04 AM, Jorge <jorge at jorgechamorro.com> wrote:
On 08/05/2011, at 05:52, Faisal Vali wrote:
(...) I find the aesthetics of the arrow-syntax far more consistent with javascript's C-based-syntactic roots than the preprocessor-tainted '#' (...)
Consistent ?
-> in C has a totally different meaning !
Yes, but that is why I alluded to a syntactic commonality and not a semantic one. But, I can see how the disparity in semantics might bother some
programmers.
Do I understand you that the idea here is 'function' without the 'function' keyword? I think this has a pretty bad backwards-incompatibility with ASI:
x = (x) { return x }
Which way should this parse?
Presumably it could be defined in the grammar so as to prohibit a newline in that very place, much like how the "return" statement is defined.
Alternatively: someone in this thread asked whether there was any purpose to blocks in ES when they aren't used for try/catch/finally or other such purposes. In other words, is there any reason not to restrict them to those use cases and thus remove this ambiguity?
Do I understand you that the idea here is 'function' without the 'function' keyword? I think this has a pretty bad backwards-incompatibility with ASI:
x = (x) { return x }
Which way should this parse?
My reading of Rick's gist was:
(x = (x) {return x})
The outer ( ) removes the ASI ambiguity. FWIW, I'm not terribly excited by this syntax, but I like it better than ->.
One thing that troubles me about the goal/movement to have a shorter "function" syntax... It seems like all the examples we exchange for it are, on principle, single-line functions. From a readability standpoint, I think it's a little deceptive to judge a syntax like that, without considering how it will look for a longer, non-trivial function. How easy will it be to scan for a function's start/end if the biggest visual signal for a function start (aka, "function") is gone and is replaced by that rather non-descript ->
which, as was said earlier in a thread, looks a lot like existing operators.
Since in the real world, functions are usually a lot more than a single return statement or a single assignment, I think we should at least keep in mind the readability (or lack thereof) of how these proposals look when there's 10, 20, 100 lines in a function... By the same token, how easy is the readability when there's 2-4 levels of nested functions (the module pattern, etc)?
On Sunday, 2011-05-08 at 20:48 , Peter Michaux wrote: On Sun, May 8, 2011 at 11:34 AM, Irakli Gozalishvili <rfobic at gmail.com> wrote:
I'd like to point out that coffeescript has a huge success and in the end it's just syntax sugared js.
Can someone give evidence that Coffeescript is actually a success? Has anyone crawled the web to determine the rate of Coffeescript adoption? (Assuming there is some way to identify Coffeescript's compiled code.) Will adoption plateau at a small percentage of total browser scripts?
Coffeescript is one of the most watched projects on github. Which I'd say is pretty big for such a young project. popular/watched
People cannot just reiterate this idea that Coffeescript is popular and use that as support for arrows without evidence that Coffeescript is actually popular.
Let's ignore popularity level for the moment, no other proposal has analog of =>
which is a solution for a real problem:
var self = this; function callback() { self.... }
Let's ignore popularity level for the moment, no other proposal has analog of
=>
which is a solution for a real problem:var self = this; function callback() { self.... }
Maybe I missed something, but didn't Brendan's #-function proposal specify
lexical this
binding, so that:
function foo() { this.bar = "baz"; return #(x){ this.bar = x; }; }
Isn't that the spirit of what => would give us?
(...)
Let's ignore popularity level for the moment, no other proposal has analog of =>
which is a solution for a real problem:
var self = this;
function callback() {
self....
}
Sorry, alternatives were evocated. If you had read my last mail (I know it was a pretty long one so I don’t blame you), you could have noticed that I proposed to use the @-syntax to perform just that. The idea would be that all lambdas would have a “bound” this (which would be the biggest distinctive between them and functions). The syntax would be the following : “@” + ( “(“ + <argument-list> + “)” )? + ( <expression> | <block> )
And it would allow to solve the “this” problem easily : element.onclick = @this.removeFromParent(); setTimeout((@alert(this)), 10);
alongside with the other common lambda usage : firstChilds = elements.map(@a.firstChild); array.reduce(@(a,b) { return (a-b)*(a+b); }); In case you need to pass a function that has not a bound this, you should continue to use the “function” keyword as usual : var anObjectHasOwnValueOf = Function.prototype.bind.call(function() { return this.hasOwnProperty(“valueOf”); }, anObject);
On Monday, 2011-05-09 at 11:02 , Kyle Simpson wrote:
Let's ignore popularity level for the moment, no other proposal has analog
of
=>
which is a solution for a real problem:var self = this; function callback() { self.... }
Maybe I missed something, but didn't Brendan's #-function proposal specify lexical
this
binding, so that:function foo() { this.bar = "baz"; return #(x){ this.bar = x; }; }
Isn't that the spirit of what => would give us?
Yes and this case makes following example extremely confusing:
MyObject.prototype.bar = #(x) { this.bar = x }
Is this instance of MyObject ? So we need to use #
in some places, but in other cases we need to stick to long form function
. I think ->
and =>
is way more intuitive and simple.
On Mon, May 9, 2011 at 10:40, Kyle Simpson <getify at gmail.com> wrote:
[snip]
One thing that troubles me about the goal/movement to have a shorter "function" syntax... It seems like all the examples we exchange for it are, on principle, single-line functions. From a readability standpoint, I think it's a little deceptive to judge a syntax like that, without considering how it will look for a longer, non-trivial function. How easy will it be to scan for a function's start/end if the biggest visual signal for a function start (aka, "function") is gone and is replaced by that rather non-descript -> which, as was said earlier in a thread, looks a lot like existing operators.
Since in the real world, functions are usually a lot more than a single return statement or a single assignment, I think we should at least keep in mind the readability (or lack thereof) of how these proposals look when there's 10, 20, 100 lines in a function... By the same token, how easy is the readability when there's 2-4 levels of nested functions (the module pattern, etc)?
Since several people have asked about and for feedback from the greater developer community and since I don't think there's a way to resolve these questions quantitatively, here's my two cents:
The main problem I'm having with declaring lambdas inline is the sheer verbosity of it. That is, I don't care about writing the code so much as reading it and stumbling upon it each and every time. You (Kyle) say that you fear for your code's readability when a shorter syntax is used for very long functions. I have exactly the opposite problem: Because of the verbosity required to express even the (otherwise) most concise statements, I declare my lambdas and then use their name to increase readability most of the time. While I agree that there are lots of cases where it's desirable to immediately see the function start, there's also lots of cases where I'd want the function itself to be nearly invisible so as to be able to focus on the contained functionality as much as possible.
Thus, I'd much rather read var onlyOdds = myArray.map(#(item) {item % 2}); or var onlyOdds = myArray.map((item) -> (item % 2));
than var onlyOdds = myArray.map(function(item) {return item % 2});
(I'd love var onlyOdds = myArray.map(item % 0); but since that's not going to work, I'm willing to settle for the next-best thing)
To be honest, I don't really care about which exact syntax gets chosen. I guess if I could freely choose, I'd go for #, but I understand the desire to save that symbol for other usages. Also, "->"
communicates intent very nicely in many cases, I think.
Andrew Dupont <mozilla at andrewdupont.net> wrote:
Presumably it could be defined in the grammar so as to prohibit a newline in that very place, much like how the "return" statement is defined.
Yeah, but that's one of the sharper corners of JS as is-- I think it would be pretty subtle and error prone. And some people might want to align their braces.
Alternatively: someone in this thread asked whether there was any purpose to blocks in ES when they aren't used for try/catch/finally or other such purposes. In other words, is there any reason not to restrict them to those use cases and thus remove this ambiguity?
This would be a serious backwards-incompatibility, and with block scoping they will become very important. My crystal ball envisions a web full of
if (true) {
...
}
;-)
Dave, Kyle, Andrew et al
Thanks for your feedback, very much appreciated. To clarify, my gist was in no way meant to be an "official" proposal of any sort, mostly for my own personal, academic benefit :)
In that spirit, I've updated the gist based on the comments and I've set a goal to implement (or at least attempt to implement) my idea using Narcissus
- again, purely for my own benefit, however I will certainly share my findings for those that might be interested.
Again, thanks for the constructive feedback!
function bodies extend as far as possible **
I see. So, a function body would be just like an if-block or loop body. One full statement, or a block. There is precedent for that in the rest of the language. So, then, this case:
x = function () y; z
would be:
x = function () { return y }; z
Is that a trick question?-) Your interpretation is one plausible extrapolation of this maximal munch rule to cover javascript's function body blocks but it might not be the only one.
In particular, you have chosen to combine maximal munch for expressions with minimal munch for statement lists, while one might want to apply maximal munch to both expressions and statement lists (if the braces around function bodies were to be made optional). One would need to look at the design options in detail before making a decision.
Javascript's handling of the statement/expression divide could do with some work, e.g., we want to be able to use functions to build control abstractions; but javascript has chosen to make assignments into expressions, and expressions into statements; javascript statements/blocks are currently not expressions, and if we tried to correct that, we'd run into the question of what to do with assignments (pass them around or execute them).
In the meantime, the only way to abstract over blocks is to wrap them in functions, so if we wanted to emulate conditional statements with conditional expressions (or other use cases where we want to work with blocks as values), we'd write something like this:
(condition ? function() { ..blockA.. } : function() { ..blockB.. })();
The use of function wrappers to delay execution is yet another motivation for concise (but readable and unambiguous) function syntax.
Claus
On May 6, 2011, at 11:22 PM, Peter Michaux wrote:
On Fri, May 6, 2011 at 11:05 PM, Andrew Dupont <mozilla at andrewdupont.net> wrote:
I don't want to get too deep into matters of taste, but I do think the current syntax is annoyingly verbose for passing lambdas as arguments in other functions. The fact that it's so verbose ends up hurting readability when the function itself is short.
I think that this is what compilers and projects like coffeescript are for. In my opinion, JavaScript itself doesn't need this new syntax.
You're free to keep writing eight characters all over the place :-|.
If you don't like reading a shorter function syntax (# has been proposed as well as ->, and I've combined the two to make #'s meaning compositional with respect to object initialisers for records and array initialisers for tuples), then shun the offending code by not reading it.
I think improving JavaScript as a compilation target is a good goal. For example, a real "lambda" with guaranteed proper tail calls, no "arguments", no need for "return",
That's what I'm proposing, ignoring control effects.
By "real 'lambda'" you must also mean new control effects, with novel runtime exceptions, e.g., for return in a lambda attempting to return out of an inactive outer function.
We've already decided several times (on this list, even) not to do that kind of lambda. IIRC Maciej's post dealt the death blow:
www.mail-archive.com/[email protected]/msg01533.html
But why in the world are you favoring new and definitely more confusing runtime semantics along with lambda syntax, while objecting to shorter function syntax that avoids ten or 12 of 14 letters?
etc would make is possible to compile Scheme to JavaScript without using something inefficient like trampolines. It would also open up recursive programming options in plain JavaScript so it would be win-win.
Yes, and we could add call/cc to make (some) compiler writers even happier. But users would shoot off all their toes with this footgun, and some implementors would be hard-pressed to support it. The point is *not * to do any one change that maximizes benefits to some parties while harming others.
Again, I claim you are not harmed by shorthands. Read them or reject them, don't use them. JS has many ways to say things, it is already multi-paradigm in shallow and deep ways.
On May 7, 2011, at 1:37 AM, Jorge wrote:
But if I wanted a shorter syntax, I would no doubt choose ruby blocks' syntax, it's even shorter yet and it's familiar already to millions of programmers.
Ruby and Smalltalk before it had blocks for most of their usable lives. JS does not. Having break, continue, return, this, arguments, and perhaps other features of JS change meaning in a block to refer to aspects of the outer function's activation (if still active) is a big change. It adds new runtime error cases. It's certainly not simpler than shorter function syntax.
Not all JS hackers are Rubyists.
On May 9, 2011, at 2:21 AM, Irakli Gozalishvili wrote:
On Monday, 2011-05-09 at 11:02 , Kyle Simpson wrote:
Isn't that the spirit of what => would give us?
Yes and this case makes following example extremely confusing:
MyObject.prototype.bar = #(x) { this.bar = x }
Is this instance of MyObject ? So we need to use
#
in some places, but in other cases we need to stick to long formfunction
. I think->
and=>
is way more intuitive and simple.
Exactly. Beyond the CoffeeScript precedent (pave the cowpaths) there is the EIBTI Python dictum. We should not add a shorthand for function that materially differs in semantics. Alex Russell argued this point with respect to # freezing and joining (that is, uniting object identity up to the nearest relevant closure). It applies to |this|-binding too.
It is hard to beed => for "lexically bound |this| function" vs. -> for "dynamically bound |this| function". I've tried. Any form that defaults to lexical-|this| and looks like a function from (...){...} on is going to mislead programmers, exaclty as you show above.
Read the whole thread. As I noted earlier today, Maciej pointed out the infelicity of a new control effect system (return, break and continue in lambda affecting the outer function, and throwing if the outer function has returned already). Waldemar observed that it is hard to beat function, except for the syntactic burden. You end up introducing something too like function to be worth it, or too strange and confusingly different in JS's statements-for-control-effects non-functionally-pure world.
You are ignoring =>.
Please do read the strawman, such as it is. Edits coming soon to clarify.
On May 9, 2011, at 2:21 AM, Irakli Gozalishvili wrote:
On Monday, 2011-05-09 at 11:02 , Kyle Simpson wrote:
Isn't that the spirit of what => would give us?
Yes and this case makes following example extremely confusing:
MyObject.prototype.bar = #(x) { this.bar = x }
Is this instance of MyObject ? So we need to use
#
in some places, but in other cases we need to stick to long formfunction
. I think->
and=>
is way more intuitive and simple.
Exactly. Beyond the CoffeeScript precedent (pave the cowpaths) there is the EIBTI Python dictum. We should not add a shorthand for function that materially differs in semantics. Alex Russell argued this point with respect to # freezing and joining (that is, uniting object identity up to the nearest relevant closure). It applies to |this|-binding too.
It is hard to beed => for "lexically bound |this| function" vs. -> for "dynamically bound |this| function". I've tried. Any form that defaults to lexical-|this| and looks like a function from (...){...} on is going to mislead programmers, exaclty as you show above.
As much as I'm opposed to the idea of keyword shortening for the sake of keyword shortening, the more i think about it, the less i like the arrow syntax.
I think I'd simply prefer a prefix character to the infix arrow operator, mostly from a readability stand point but i have a few other issues i'll go into later. When I read the examples in the wiki I simply find it unpleasant and difficult, I can't put my finger on the specific reason either alas :(
I think I'd prefer the #{ expr } or #(args...){ expr } syntaxes simply to ease linear reading of code. That said they seem to introduce ambiguity with the Records strawman, but on the other hand i'm not too fond of records or even really the tuple strawmen so maybe this isn't necessarily problem.
That said this is kind of bikeshed-y (as B said in twitter)
Honestly these are the big issues I see in JS.current that I'd like to see fixed in JS.next:
- Array functions (and by proxy list comprehensions) all return Arrays. I think fixing this is necessary, esp. in the context of iterators existing.
- for in enumeration with iterators is an icky problem that needs to be resolved.
- Generalised object subtyping
- Probably Mark's simple map and set APIs -- these can be implemented in JS, but I suspect much more efficiently by the host vm. I thought about just doing hashCode() (or whatever) but i'm not sure how v8 would do the hashcodes without obviously increasing memory use. I presume it's a solved problem (as Java and .NET etc can do it) but a quick Bing (i shall make this a verb!!) for details didn't seem to show much useful info.
On 5/10/11, Oliver Hunt <oliver at apple.com> wrote: [...]
I think I'd prefer the #{ expr } or #(args...){ expr } syntaxes simply to\
What good is Arguments?
[...]
- Generalised object subtyping
- Probably Mark's simple map and set APIs -- these can be implemented in\
If it's wish list time, then I'll say triple quotes:
div.innerHTML = """ <span id="foo" class='bar'>#str</span> """; (if not, then I apologize fro being off topic).
I have to say that I was a bit indifferent about the different syntaxes on offer until I had a good look at the strawman, and found that there were differences between -> => and #(x)->(x*x); with to |this| binding. I have to admit that at the moment, exactly what those subtleties are, is a little over my head at the moment.
But given I have to explain |this| again stackoverflow.com/questions/1085674/where-is-my-this-using-objects-method-as-a-callback-function/1085715#1085715 and again stackoverflow.com/questions/5639451/why-this-is-not-this/5692094#5692094 and again...
I appreciate efforts to address the |this| problem. I think though, that in terms of familiarity, "bind" already effectively solves that specific issue. The # operator seems too much like ambient magic to me.
Broadly, I like how the arrow syntax resembles mathematical notation for "functional dependency", much like the original function syntax resembles mathematical notation for "function". Given some time, I don't think it would be hard to get used to. But it might scare some programmers easily spooked by "weird" syntax. We're the experts, the language designers (you), and the advanced users (me and others), who are drawn to and appreciate javascript due to its resemblance to scheme and haskell etc. etc. so the arrow syntax appeals to us on that level. But one of the strengths of Javascript has been as a syntactical trojan horse- Getting these nice qualities under the noses of people who would otherwise find that stuff unpalatable. For this reason, as much as I like arrow syntax, and attempts to address |this| scoping, I have to lean towards #(x){x*x}, and us syntactical snobs can still have coffeescript.
I still wish there was a way to make |this| less confusing though. I'm sure you do too.
To Oliver's point: I think this would qualify as bikeshedding if this didn't really matter. It is a tiny detail, but an important one, so it makes sense that we've spent so long discussing it.
I acknowledge the arrow notation's advantages over #: (a) we've got precious few ASCII characters left and the octothorp has been claimed by several strawmen; (b) the proposed octothorp syntax doesn't solve the ->/=> thing (having a concise syntax for binding functions to current scope); (c) prior art of CoffeeScript.
I'm not completely sold on it, though, for a couple of reasons: (a) the "cost" of typing an arrow on a western keyboard is much higher than the cost of an octothorp; (b) the ->/=> distinction is, I think, too subtle. Rebinding dramatically changes the meaning of the function, so I'd prefer if the notation guaranteed that a user couldn't gloss over that by mistaking -> for => or vice/versa.
To rephrase that second point: I think it's a good idea to have a shorthand syntax for .bind(this)
, but it has to make itself more obvious than the arrow notation proposes. And there's nothing precluding a similar syntax for the octothorp (e.g., #(x){ this.foo }
vs. ##(x){ this.foo }
— retaining Brendan's point that the rebinding syntax should be "fatter").
(Also, for the purposes of this argument, I'm fine with using another of our free ASCII characters in place of the octothorp.)
On May 10, 2011, at 4:06 PM, Andrew Dupont wrote:
To Oliver's point: I think this would qualify as bikeshedding if this didn't really matter. It is a tiny detail, but an important one, so it makes sense that we've spent so long discussing it.
I acknowledge the arrow notation's advantages over #: (a) we've got precious few ASCII characters left and the octothorp has been claimed by several strawmen;
We could kill those strawmen. /me hides :D
(b) the proposed octothorp syntax doesn't solve the ->/=> thing (having a concise syntax for binding functions to current scope); (c) prior art of CoffeeScript.
I don't consider coffee script to be sufficiently widely used to really consider this a valid use case. \ is a much more common lambda symbol in many languages, and i'm not sure what the ambiguity would be in {...} or (...){...}.
I'm also really not happy with the concept of minor variances in syntax having such dramatic impact the language semantics. All the fiddling with |this| dramatically increases the complexity of the language, it doesn't simplify it.
I'm not completely sold on it, though, for a couple of reasons: (a) the "cost" of typing an arrow on a western keyboard is much higher than the cost of an octothorp;
I think this kind of "cost" isn't really that important (i seem to deviate from the rest of TC39 in this regard). The logical progression of this is to replace all "long" keywords with short form characters, thus converting JS code from it's remarkable legibility (Relative to many other scripting languages) into a perl/ruby/APL like monster where people can right "compact" and "elegant" code in such a way as to render it impenetrable to new comers. (For example it is possible to write reasonable readable perl for people who don't know much perl, but the majority could be used as an alien script in a C-list scifi movie :D )
(b) the ->/=> distinction is, I think, too subtle. Rebinding dramatically changes the meaning of the function, so I'd prefer if the notation guaranteed that a user couldn't gloss over that by mistaking -> for => or vice/versa.
Agreed. But of course I don't like any of the messing with |this| binding.
On Tue, May 10, 2011 at 16:22, Oliver Hunt <oliver at apple.com> wrote:
\ is a much more common lambda symbol in many languages, and i'm not sure what the ambiguity would be in {...} or (...){...}.
(a,b,c) { a + b * c }
That's cute.
I'm also really not happy with the concept of minor variances in syntax having such dramatic impact the language semantics. All the fiddling with |this| dramatically increases the complexity of the language, it doesn't simplify it.
I completely agree. It think any short-form function syntax should have the exact same semantics as the existing long-form. We've got .bind(obj). That's enough.
On May 10, 2011, at 4:27 PM, Isaac Schlueter wrote:
On Tue, May 10, 2011 at 16:22, Oliver Hunt <oliver at apple.com> wrote:
\ is a much more common lambda symbol in many languages, and i'm not sure what the ambiguity would be in {...} or (...){...}.
(a,b,c) { a + b * c }
That's cute.
Oliver still has a crush on Haskell.
I've mooted \ along with ƒ, etc. for a while. \ is bad for readability because it's visually light, but worse, if we want named function expression shorthand, then \u10A0(){} is a valid Unicode-identifier-char-named function expression.
Last time we talked about \ in TC39 for shorter function syntax it died hard, IIRC.
I'm also really not happy with the concept of minor variances in syntax having such dramatic impact the language semantics. All the fiddling with |this| dramatically increases the complexity of the language, it doesn't simplify it.
I completely agree. It think any short-form function syntax should have the exact same semantics as the existing long-form. We've got .bind(obj). That's enough.
No, there are more efficient ways to implement something with dedicated syntax, such as CoffeeScript's =>, and it comes up enough that '.bind(this)', ignoring optimization difficulty, is too much.
The long-standing way to code lexical this is 'var self = this; ... function (...) {... self ... }'. That won't go away, but it is also crying for a shorthand.
What makes 'var self = this;' particularly bad is when the inner function is named, and all its calls are via that unqualified name.
In such a scenario, ES5 strict's rule of binding |this| to undefined just wastes the |this| parameter, and requires 'var self = this' or '.bind(this)' as heavyweight workarounds.
if (a)->x is going to be a function that doesn't capture 'this', I'd
prefer (a)+>x for capturing 'this'. they're visually distinct,
somewhat mnemonic, about equally easy/hard to type.
2011/5/10 Oliver Hunt <oliver at apple.com>:
As much as I'm opposed to the idea of keyword shortening for the sake of keyword shortening, the more i think about it, the less i like the arrow syntax.
I think I'd simply prefer a prefix character to the infix arrow operator, mostly from a readability stand point but i have a few other issues i'll go into later. When I read the examples in the wiki I simply find it unpleasant and difficult, I can't put my finger on the specific reason either alas :(
I think I'd prefer the #{ expr } or #(args...){ expr } syntaxes simply to ease linear reading of code. That said they seem to introduce ambiguity with the Records strawman, but on the other hand i'm not too fond of records or even really the tuple strawmen so maybe this isn't necessarily problem.
That said this is kind of bikeshed-y (as B said in twitter)
Honestly these are the big issues I see in JS.current that I'd like to see fixed in JS.next: * Array functions (and by proxy list comprehensions) all return Arrays. I think fixing this is necessary, esp. in the context of iterators existing. * for in enumeration with iterators is an icky problem that needs to be resolved. * Generalised object subtyping * Probably Mark's simple map and set APIs -- these can be implemented in JS, but I suspect much more efficiently by the host vm. I thought about just doing hashCode() (or whatever) but i'm not sure how v8 would do the hashcodes without obviously increasing memory use. I presume it's a solved problem (as Java and .NET etc can do it) but a quick Bing (i shall make this a verb!!) for details didn't seem to show much useful info.
We already have getters and setters in the API for an identity hash code. It adds an invisible property to the object (not value). This can cause the object to expand and change 'hidden class' in much the same way as would happen if someone just did o.hashCode = Math.random(). If the hash code is not visible to the JS code then maps could be done in other ways than with a hash code, eg. rehashing when objects move.
I can see you are thinking of using the address of the object as a hash code. This can work, and early Java VMs did it, but there is a nasty gotcha: You can't leak this hash code to JS code in any way, because then you just defeated ASLR and leaked very valuable information to any attacker hoping to use buffer overflows to overwrite adjacent objects. You could xor all hash codes with a nonce, but it wouldn't be hard for the attacker to find the low bits of that nonce. I'm not sure whether you could recover the high bits somehow.
Also you put an extra barrier in the way of a moving GC if you do it that way.
On May 11, 2011, at 12:55 AM, Erik Corry wrote:
2011/5/10 Oliver Hunt <oliver at apple.com>:
As much as I'm opposed to the idea of keyword shortening for the sake of keyword shortening, the more i think about it, the less i like the arrow syntax.
I think I'd simply prefer a prefix character to the infix arrow operator, mostly from a readability stand point but i have a few other issues i'll go into later. When I read the examples in the wiki I simply find it unpleasant and difficult, I can't put my finger on the specific reason either alas :(
I think I'd prefer the #{ expr } or #(args...){ expr } syntaxes simply to ease linear reading of code. That said they seem to introduce ambiguity with the Records strawman, but on the other hand i'm not too fond of records or even really the tuple strawmen so maybe this isn't necessarily problem.
That said this is kind of bikeshed-y (as B said in twitter)
Honestly these are the big issues I see in JS.current that I'd like to see fixed in JS.next:
- Array functions (and by proxy list comprehensions) all return Arrays. I think fixing this is necessary, esp. in the context of iterators existing.
- for in enumeration with iterators is an icky problem that needs to be resolved.
- Generalised object subtyping
- Probably Mark's simple map and set APIs -- these can be implemented in JS, but I suspect much more efficiently by the host vm. I thought about just doing hashCode() (or whatever) but i'm not sure how v8 would do the hashcodes without obviously increasing memory use. I presume it's a solved problem (as Java and .NET etc can do it) but a quick Bing (i shall make this a verb!!) for details didn't seem to show much useful info.
We already have getters and setters in the API for an identity hash code. It adds an invisible property to the object (not value). This can cause the object to expand and change 'hidden class' in much the same way as would happen if someone just did o.hashCode = Math.random(). If the hash code is not visible to the JS code then maps could be done in other ways than with a hash code, eg. rehashing when objects move.
I was actually thinking of object pointers from the PoV of guaranteeing uniqueness of hashcode, which of course isn't actually a requirement (facepalm)
I can see you are thinking of using the address of the object as a hash code. This can work, and early Java VMs did it, but there is a nasty gotcha: You can't leak this hash code to JS code in any way, because then you just defeated ASLR and leaked very valuable information to any attacker hoping to use buffer overflows to overwrite adjacent objects. You could xor all hash codes with a nonce, but it wouldn't be hard for the attacker to find the low bits of that nonce. I'm not sure whether you could recover the high bits somehow.
I was aware of those issues, essential plan had been one-way unique hash from address which as above is not necessary as you just need to have a fixed hashcode for the object :)
Also you put an extra barrier in the way of a moving GC if you do it that way.
I know, which is why i was wondering how V8 did it, given that it obviously "required" the object pointer (see above re: facepalm)
See also
proposals:hashcodes and especially proposals:hashcodes#a_note_regarding_security
which date from ES4, and
strawman:encapsulated_hashcodes
which needs updating.
On May 7, 2011, at 2:39 PM, Claus Reinke wrote:
Consider this: w = (x)->y || z That code is not obvious at all. Which of these would it be? 1: w = function (x) { return y } || z 2: w = function (x) { return y || z } It seems to me that there must be some sort of delineation around the function start and end.
Either that, or around the function body (expression or statement).
But such delineation does not have to lead to required syntax in the function construct. Such required delineations were not part of lambda-calculus originally **, they arose out of implementation limitations that can be overcome.
We're talking JS syntax here, not anything like the original Lambda calculus or s-expressions.
I know that takes some getting used to (been there myself*), but there is an established standard, both in publications on programming language theory, and in some real languages: function bodies extend as far as possible **
So your examples would be
1: w = (function (x) return y) || z 2: w = (function (x) return y || z)
This does not work, because the ECMA-262 grammar simplifies to something like this toy bison grammar:
%token FUNCTION %token NUMBER
%%
Expr: Expr '+' Term | Term ;
Term: Term '*' Fact | Fact '(' ')' | Fact ;
Fact: FUNCTION '(' ')' '{' Expr '}' | '(' Expr ')' | NUMBER ;
Notice this grammar parses function expressions with empty parameter lists, and function calls with empty argument lists. No statements, only expressions, and only numbers with addition and multiplication (and numbers are syntactically callable, as in JS), but the essential grammatical structure remains.
Now let's try to extend it to allow an unbraced body for the analogue of ES5's PrimaryExpression, here called Fact:
%token FUNCTION %token NUMBER
%%
Expr: Expr '+' Term | Term ;
Term: Term '*' Fact | Fact '(' ')' | Fact ;
Fact: FUNCTION '(' ')' Fact | '(' FUNCTION '(' ')' Expr ')' | '(' Expr ')' | NUMBER ;
That is, we allow an unparenthesized high-precedence expression (a Fact) as the body of a function expression, or else require parentheses around an entire function expression whose body is an unparenthesized low-precedence expression (an Expr).
The results in reduce/reduce conflicts:
state 23
4 Term: Fact . '(' ')'
5 | Fact .
6 Fact: FUNCTION '(' ')' Fact .
'(' shift, and go to state 13
'+' reduce using rule 5 (Term)
'+' [reduce using rule 6 (Fact)]
'*' reduce using rule 5 (Term)
'*' [reduce using rule 6 (Fact)]
'(' [reduce using rule 6 (Fact)]
')' reduce using rule 5 (Term)
')' [reduce using rule 6 (Fact)]
$default reduce using rule 5 (Term)
In other words, we've created a hopeless ambiguity between an unparenthesized function expression with a high-precedence body expression and a parenthesized-on-the-outside function expression with a low-precedence body.
There's a shift/reduce conflict too, but that is not the concern here. The problem is that no amount of lookahead can decide by which production to reduce. We must give up one of the two function expression forms.
One might be tempted to make an unparenthesized (on the outside) function expression with an unparenthesized expression body be a low-precedence expression (say, AssignmentExpression), but then it can't be used as the callee part of a CallExpression without being parenthesized. Such a low-precedence function expression would have to be parenthesized with every operator save comma.
In practice, function expressions aren't operated on except by being on the right-hand side of assignment, by calling them to make a CallExpression, and by concatenating their string conversions, but requiring parens for all sub-expression uses of function expressions is a big break from ECMA-262's grammar since ES3, which introduced function expressions as PrimaryExpressions (highest precedence).
Here is a more complete toy ES sub-grammar, still not too big:
%token FUNCTION %token IDENT %token NUMBER %token PLUSPLUS
%%
Expr: Expr '+' Term | Term ;
Term: Term '*' Fact | Fact ;
Fact: PLUSPLUS Fact | Post ;
Post: Call PLUSPLUS | Call ;
Call: Call '(' ')' | Prim ;
Prim: FUNCTION '(' ')' '{' Expr '}' | '(' Expr ')' | IDENT | NUMBER ;
If we make the mistake ES4 made (implemented in SpiderMonkey still) of adding a Prim(aryExpression) right-hand side:
Prim: FUNCTION '(' ')' Expr
to allow unbraced expression bodies for function expressions, the low-precedence Expr at the end of high-precedence Prim makes a nasty loop in the grammar. Waldemar pointed this out a while ago (www.mail-archive.com/[email protected]/msg01008.html). His counter-example used a "let" expression, but there's a function expression equivalent:
function () a ? f : x++();
Per the full ES grammar, and the toy just above, you cannot call a postfix-++ expression. But the whole of |function () a ? f : x++| should be a function expression with an unparenthesized Expr body, per the added right-hand side. And a function expression should be callable without having to be parenthesized, since it is a Prim(aryExpression).
This pretty much dooms arrow syntax to either requiring parentheses or braces around the arrow-function's body, always (one or the other; there's a separate issue with object initialisers Doug raised, I'll deal with it in a separate message); or else require parentheses or some other bracketing (as Isaac pointed out re: Ruby-ish blocks) on the outside. No way to be paren-free.
BTW, "maximal munch" refers to lexing, a DFA thing. Not to parsing regular languages, which requires a stack to decide how to recognize sentences in the language based on their prefixes and one or more tokens of lookahead.
Anyway, even though JS's grammar does not allow us to reason about function syntax as if we had the lambda calculus, I appreciated your attempt to deal with the cases Isaac came up with. I wish we could parse a low-precedence unparenthesized function body expression. It does not look feasible.
On May 13, 2011, at 2:52 PM, Brendan Eich wrote:
One might be tempted to make an unparenthesized (on the outside) function expression with an unparenthesized expression body be a low-precedence expression (say, AssignmentExpression), but then it can't be used as the callee part of a CallExpression without being parenthesized. Such a low-precedence function expression would have to be parenthesized with every operator save comma.
CoffeeScript does something like this. It separates Invocation from Operation (both are Expressions, and an Operation combines Expressions using operators, sometimes with a narrower non-terminal than Expression on the left of a dyadic operator).
Invocations can be chained but the basis case is a Value as callee nonterminal, and a Value must be parenthesized if it contains Code. The Code nonterminal produces a CoffeeScript function expression, with optional parenthesized parameter list, arrow (-> or =>), and a block body.
The ECMA-262 grammar could be extended like this. It would mean -> and => as proposed in strawman:arrow_function_syntax would not be sugar for existing function expression (with .bind or some tamper-proof internal equivalent in the case of =>). But that seems better than requiring parentheses.
This grammar interlude reminds me of the grammar dependency graphs at blog.nicksieger.com/articles/2006/10/27/visualization-of-rubys-grammar -- the Java and JavaScript grammars show the C-family expression sub-grammar-dependency tower (duplicated in JS's case due to the NoIn productions), with all those precedence levels we know and love. Ruby has a flatter graph with a popular "primary" non-terminal in the middle.
www.flickr.com/photos/nicksieger/280661836/sizes/o/in/photostream (warning: BIG)
I'll update strawman:arrow_function_syntax to include an ES5 grammar patch.
The Ruby-ish block (Allen's lambda syntax proposal) approach has to be considered, still, since it has braces around the outside and avoids all this grammar hacking. The downside is an empty "block" has to be distinguished from an empty object initialiser (from an empty block statement :-P). That may not be a big downside as Allen noted, although I don't think undefined or null can stand in for empty block.
On May 13, 2011, at 11:25 PM, Brendan Eich wrote:
I'll update strawman:arrow_function_syntax to include an ES5 grammar patch.
Done: strawman:arrow_function_syntax, specifically strawman:arrow_function_syntax#grammar_changes
This requires splitting the sub-grammar starting at Expression (comma expression), at AssignmentExpression (which occurs in all comma-separated list non-comma-expression contexts, namely argument lists and initialisers), creating a parallel production chain from Statement through AssignmentStatement.
Many languages restrict assignment to statement form. We don't need to do that and shouldn't break extant code that nests assignment expressions, but separating assignment statements (comma-separated lists of assignments) enables better right-hand side syntax for arrow function expressions -- namely, they don't have to be parenthesized.
Thus you can write
array.map((elem) -> elem * elem)
let identity = (x) -> x;
thrice = (x) -> 3 * x;
without gratuitous parenthesization. Calling an arrow function expression requires parentheses on the outside, of course:
alert((-> "paren me")());
Comments welcome, I haven't had time to formalize and test this but it looks like it will work.
/be
Grammar Changes
Change all uses of AssignmentExpression outside of the Expression sub-grammar to InitialExpression:
ElementList : // See 11.1.4 Elisionopt InitialExpression ElementList , Elisionopt InitialExpression ... PropertyAssignment : // See 11.1.5 PropertyName : InitialExpression ... ArgumentList : // See 11.2 InitialExpression ArgumentList , InitialExpression ... Initialiser : // See 12.2 = InitialExpression
InitialiserNoIn : // See 12.2 = InitialExpressionNoIn Define InitialExpression and ArrowFunctionExpression:
InitialExpression : AssignmentExpression ArrowFunctionExpression
ArrowFunctionExpression : FormalParametersOpt Arrow [lookahead ∉ {{}] InitialExpression FormalParametersOpt Arrow Block
FormalParameters : ( FormalParameterListOpt )
Arrow : one of -> or =>
Split assignment out of ExpressionStatement into AssignmentStatement:
Statement : Block VariableStatement EmptyStatement AssignmentStatement ExpressionStatement ...
AssignmentStatement : [lookahead ∉ {{, function}] AssignmentList ;
AssignmentList : Assignment AssignmentList , Assignment
Assignment : LeftHandSideExpression = InitialExpression LeftHandSideExpression AssignmentOperator InitialExpression
ExpressionStatement : [lookahead ∉ {{, function}] ConditionalExpression ; Finally, PrimaryExpression produces a parenthesized ArrowFunctionExpression:
PrimaryExpression : ... ( ArrowFunctionExpression )
On 15.05.2011 10:33, Brendan Eich wrote:
On May 13, 2011, at 11:25 PM, Brendan Eich wrote:
I'll update strawman:arrow_function_syntax to include an ES5 grammar patch.
Done: strawman:arrow_function_syntax, specifically strawman:arrow_function_syntax#grammar_changes
This requires splitting the sub-grammar starting at Expression (comma expression), at AssignmentExpression (which occurs in all comma-separated list non-comma-expression contexts, namely argument lists and initialisers), creating a parallel production chain from Statement through AssignmentStatement.
Many languages restrict assignment to statement form. We don't need to do that and shouldn't break extant code that nests assignment expressions, but separating assignment statements (comma-separated lists of assignments) enables better right-hand side syntax for arrow function expressions -- namely, they don't have to be parenthesized.
Thus you can write
array.map((elem) -> elem * elem) let identity = (x) -> x; thrice = (x) -> 3 * x;
without gratuitous parenthesization. Calling an arrow function expression requires parentheses on the outside, of course:
alert((-> "paren me")());
Comments welcome, I haven't had time to formalize and test this but it looks like it will work.
Cool!
// 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);
So, ES3 joined-objects are back. Though, the question is in their [[Scope]] difference (i.e. can be they joined in the following case):
let foo = (args...) -> { return #(a) -> args.map(a); };
foo(1, 2, 3)((x) -> x * x); // [1, 4, 9]
foo(5, 10)((x) -> x * x); // [25, 10]
Do both have the same (reflected) [[Scope]] to be joined? At first glance with named args, e.g. foo(a, b, c) yes, but what's with rest args?
Other things seems fine.
Dmitry.
On May 15, 2011, at 8:14 AM, Dmitry A. Soshnikov wrote:
// 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); So, ES3 joined-objects are back. Though, the question is in their [[Scope]] difference (i.e. can be they joined in the following case):
The "join to nearest relevant closure" words were meant to address this. Let's see (I made a few typo and syntax fixes):
let foo = (...args) -> { return #(a) -> args.map(a); };
foo(1, 2, 3)((x) -> x * x); // [1, 4, 9]
foo(5, 10)((x) -> x * x); // [25, 100]
Do both have the same (reflected) [[Scope]] to be joined?
The two foo calls have different unjoinable scope chains enclosing variables captured by the returned #(a) -> args.map(a) function, specifically args. So that hash-frozen arrow-function cannot be joined into one identity.
At first glance with named args, e.g. foo(a, b, c) yes, but what's with rest args?
Named vs. rest doesn't matter, the question is lexical capture. The name |args| is from the outer
(...args) -> { return #(a) -> args.map(a); }
function. It is used in the inner arrow function.
The location of this |args| parameter is what is actually captured in general. This is optimizable to copying the value at that location in many cases, including this one, but that doesn't change the fact that the location varies with each call to foo.
So args' abstract location differs, and therefore its value may differ, each time the inner arrow-function is evaluated. So the # freezes it but it will not be joined with other evaluations of the same source form.
However you implement closures, something has to vary each time the inner arrow is evaluated, to capture the correct args, [1, 2, 3] or [5, 10].
On May 14, 2011, at 11:33 PM, Brendan Eich wrote:
Grammar Changes Change all uses of AssignmentExpression outside of the Expression sub-grammar to InitialExpression:
... ArrowFunctionExpression : FormalParametersOpt Arrow [lookahead ∉ {{}] InitialExpression FormalParametersOpt Arrow Block
FormalParameters : ( FormalParameterListOpt )
Forgot to include the optional leading |this| parameter, so the above two production-sets should be:
ArrowFunctionExpression : ArrowFormalParametersOpt Arrow [lookahead ∉ {{}] InitialExpression ArrowFormalParametersOpt Arrow Block
ArrowFormalParameters : ( FormalParameterListOpt ) ( this InitialiserOpt ) ( this InitialiserOpt , FormalParameterList )
("Opt" at the end is because I can't get dokuwiki to do a subscripted "opt" as ES1-5's grammars do for optional right-hand side terms -- at least not without a dokuwiki plugin.)
Ok, final and most delicate part of the mission here: allow (v) -> {k: v} and even -> {} to return objects, not make useless block statements.
// 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};
Thanks to Doug for pushing on this idea. I believe that it is sound (still to be formalized and tested mechanically) in a bottom-up parser.
The top-down approach by default is to parse a cover grammar until an unambiguous decision point is reached, then depending on the decision, rewrite the AST (e.g., to make a labeled statement in a block instead of an object initializer).
/be
On May 15, 2011, at 10:26 AM, Brendan Eich wrote:
On May 14, 2011, at 11:33 PM, Brendan Eich wrote:
Grammar Changes
To enable unparenthesized ObjectLiteral expressions as bodies of arrow functions, without ambiguity with Block bodies, restrict LabelledStatement as follows:
LabelledStatement : Identifier : LabelledStatement Identifier : LabelUsingStatement
LabelUsingStatement : NonEmptyBlock IfStatement IterationStatement BreakStatement SwitchStatement TryStatement
NonEmptyBlock : // See 12.1 { StatementList } The resulting grammar should be unambiguously LR(1) (ignoring ASI), because { L: expr...} can parse only as an ObjectLiteral, and { L: { if (cond)... } } or similar LabelUsingStatement variations can parse only as a LabelledStatement.
TODO: evaluate top-down parsing difficulty
On 15.05.2011 21:09, Brendan Eich wrote:
On May 15, 2011, at 8:14 AM, Dmitry A. Soshnikov wrote:
// 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); So, ES3 joined-objects are back. Though, the question is in their [[Scope]] difference (i.e. can be they joined in the following case): The "join to nearest relevant closure" words were meant to address this. Let's see (I made a few typo and syntax fixes):
let foo = (...args) -> { return #(a) -> args.map(a); };
foo(1, 2, 3)((x) -> x * x); // [1, 4, 9]
foo(5, 10)((x) -> x * x); // [25, 100]
Do both have the same (reflected) [[Scope]] to be joined? The two foo calls have different unjoinable scope chains enclosing variables captured by the returned #(a) -> args.map(a) function, specifically args. So that hash-frozen arrow-function cannot be joined into one identity.
At first glance with named args, e.g. foo(a, b, c) yes, but what's with rest args? Named vs. rest doesn't matter, the question is lexical capture. The name |args| is from the outer
(...args) -> { return #(a) -> args.map(a); }
function. It is used in the inner arrow function.
The location of this |args| parameter is what is actually captured in general.
Oh, my misunderstanding then. Then I just incorrectly treated yours
assert(p === q);
I though here you try to show that the engine will handle the case with optimization and reuse (i.e. to join) the function object. However, it still not possible because of different scope chain, that exactly why I was asking.
So you mean just lexical addressing of free variable? I.e. without
dynamic scope chain lookup (that what Dave Herman confused recently with
dynamic scope concept IIRC). However it's interesting -- if ES6 will
have lexical addressing anyway (that is there will be no dynamic
bindings -- no eval
, no with
, etc, -- just compile-time bindings),
this means that this optimization will be done in any way, -- without
needing of this #function in this case. Or am I mistaken again?
Thanks for explanations btw.
Dmitry.
Oh, and just a small note -- perhaps there's a sense to put a comment near each line to what result the expression evaluates in your examples, e.g.
asset(p === q); // true (or false?)
etc.
Dmitry.
On May 15, 2011, at 11:55 AM, Dmitry A. Soshnikov wrote:
Oh, my misunderstanding then. Then I just incorrectly treated yours
assert(p === q);
This was from
// 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);
and the assertion means what it seems: p is identical to q.
I though here you try to show that the engine will handle the case with optimization and reuse (i.e. to join) the function object.
I'm not talking about optimization -- this is a case where joining works, since the function is pure. It closes over no outer variables' locations.
However, it still not possible because of different scope chain, that exactly why I was asking.
No, that's not what the strawman says, and not what I said last time. The issue is not different scope chains, it is whether there are captured closure variables whose abstract locations are not invariant with respect to the source function expression in question.
Each evaluation of a given function expression gives a fresh object in JS today. WIth joining as Mark proposed at
strawman:const_functions#joining
and with opt-in syntax (the # prefix) as I'm proposing, this "fresh function object for each evaluation of a function expression" rule would no lot apply.
On May 15, 2011, at 11:56 AM, Dmitry A. Soshnikov wrote:
Oh, and just a small note -- perhaps there's a sense to put a comment near each line to what result the expression evaluates in your examples, e.g.
asset(p === q); // true (or false?)
That is confusing and pointless. I meant what I wrote. The assertions are intended to claim that their argument conditions are truthy.
See last reply for more on joining. It occurs to me you thought scope chain varying in the context of a pure hash-rocket such as #->42 means that function cannot be joined, but since it is pure, it need not entrain its scope chain as an internal [[Scope]] property.
More, since # freezes, there's no need for it to be duplicated, since there is no mutation side channel.
So strawman:arrow_function_syntax proposes freezing and joining, only if the user specifies via the # prefix.
Could I trouble you to confirm or clarify the semantics of the following constructs*:
let f = -> -> 3; // well-formed?
let x = f()(); // x is equal to 3 right?
let global = this;
let o = {}; o.fat = => this;
o.thin = -> this;
assert( o.fat() === global); // true? assert( o.thin() === o); // true?
o.thin_then_fat = -> => this;
o.fat_then_thin = => -> this;
assert(o.thin_then_fat()() === o); // true? assert(o.fat_then_thin()() === global); // true?
Thanks!
*(based on the arrow syntax proposal strawman:arrow_function_syntax)
On 16.05.2011 0:37, Brendan Eich wrote:
On May 15, 2011, at 11:55 AM, Dmitry A. Soshnikov wrote:
Oh, my misunderstanding then. Then I just incorrectly treated yours
assert(p === q); This was from
// 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);
and the assertion means what it seems: p is identical to q.
I though here you try to show that the engine will handle the case with optimization and reuse (i.e. to join) the function object. I'm not talking about optimization -- this is a case where joining works, since the function is pure. It closes over no outer variables' locations.
However, it still not possible because of different scope chain, that exactly why I was asking. No, that's not what the strawman says, and not what I said last time. The issue is not different scope chains, it is whether there are captured closure variables whose abstract locations are not invariant with respect to the source function expression in question.
Each evaluation of a given function expression gives a fresh object in JS today. WIth joining as Mark proposed at
Got it. Though it still seems to me as just an implementation optimization without need to specify explicitly that a function is closed (without free variables) and thus can be optimized, i.e. created once and stored as some internal property.
Dmitry.
On 16.05.2011 0:40, Brendan Eich wrote:
On May 15, 2011, at 11:56 AM, Dmitry A. Soshnikov wrote:
Oh, and just a small note -- perhaps there's a sense to put a comment near each line to what result the expression evaluates in your examples, e.g.
asset(p === q); // true (or false?) That is confusing and pointless. I meant what I wrote. The assertions are intended to claim that their argument conditions are truthy.
Yeah, OTOH, yes.
See last reply for more on joining. It occurs to me you thought scope chain varying in the context of a pure hash-rocket such as #->42 means that function cannot be joined, but since it is pure, it need not entrain its scope chain as an internal [[Scope]] property.
More, since # freezes, there's no need for it to be duplicated, since there is no mutation side channel.
So strawman:arrow_function_syntax proposes freezing and joining, only if the user specifies via the # prefix.
Yep, I got it, thanks, though, as mentioned seems it can be managed then at engine level without explicit specifying by the user, no?
Dmitry.
On May 15, 2011, at 1:49 PM, Faisal Vali wrote:
Could I trouble you to confirm or clarify the semantics of the following constructs*:
let f = -> -> 3; // well-formed? let x = f()(); // x is equal to 3 right?
Sure, unambiguous. Same as in CoffeeScript:
coffee> f = -> -> 3; [Function] coffee> f()()
3
let global = this;
let o = {}; o.fat = => this; o.thin = -> this;
assert( o.fat() === global); // true?
Sure, or (no need for global) assert(o.fat() === this).
assert( o.thin() === o); // true?
Yes.
o.thin_then_fat = -> => this;
This example is given in strawman:arrow_function_syntax -- look for "method:".
o.fat_then_thin = => -> this;
assert(o.thin_then_fat()() === o); // true?
Right, as in the strawman.
assert(o.fat_then_thin()() === global); // true?
No. Since the proposed syntax is just syntax, you can expand it and evaluate:
o.fat_then_thin = (function () { return function () { return this; }; }).bind(this);
So the first call,
o.fat_then_thin() indeed returns function () { return this; } from a function in which |this| was bound to the outermost |this|, aliased via |global|.
But that (function () { return this; }) result is then immediately invoked and the |this| it receives, per ES5 strict and Harmony, is undefined.
That's why I focused on the thin-then-fat example in the strawman. To show fat-then-thin with |this| dynamically bound on the second call (to the "inner" thin arrow function), you might need to store the return value of the first (outer, o.fat_then_thin()) call as a property value, and call it that way. Or via .call/.apply. Or as you did here, but it is less clear to have an undefined |this| pop out at the end.
Again, strawman:arrow_function_syntax is "just syntax". Therefore since -> does not bind |this|, that parameter is bound dynamically depending on the callee sub-expression of the call expression. Same as for long function syntax with ES5 strict semantics.
On May 15, 2011, at 1:52 PM, Dmitry A. Soshnikov wrote:
Each evaluation of a given function expression gives a fresh object in JS today. WIth joining as Mark proposed at
Got it. Though it still seems to me as just an implementation optimization without need to specify explicitly that a function is closed (without free variables) and thus can be optimized, i.e. created once and stored as some internal property.
We would want to specify the optimization in order to make === and egal constant time (i.e., based on pointer not value comparison). This matters for WeakMaps keyed by joined functions.
On May 15, 2011, at 1:54 PM, Dmitry A. Soshnikov wrote:
See last reply for more on joining. It occurs to me you thought scope chain varying in the context of a pure hash-rocket such as #->42 means that function cannot be joined, but since it is pure, it need not entrain its scope chain as an internal [[Scope]] property.
More, since # freezes, there's no need for it to be duplicated, since there is no mutation side channel.
So strawman:arrow_function_syntax proposes freezing and joining, only if the user specifies via the # prefix.
Yep, I got it, thanks, though, as mentioned seems it can be managed then at engine level without explicit specifying by the user, no?
Do you mean that users shouldn't have to write # prefixes to get joining? That is hard. SpiderMonkey implements joining for lambdas that do not close over outer lexical variables provided those lambdas are used as the initializer of a property in an object literal, or as the full RHS of assignment to a property of an Object instance. This optimization wins but it requires read and write barriers (which we already have for getters and setters in general). It's complex.
The # prefix means freeze too, and that is required for joining. ES3 left it to implementations to join but that was a mistake that (if implementations had done so; none did after early SpiderMonkey bugs were fixed) creates a mutation side channel. See also the ES3 global regexp singleton per lexical regular expression bug.
On 16.05.2011 1:47, Brendan Eich wrote:
On May 15, 2011, at 1:54 PM, Dmitry A. Soshnikov wrote:
See last reply for more on joining. It occurs to me you thought scope chain varying in the context of a pure hash-rocket such as #->42 means that function cannot be joined, but since it is pure, it need not entrain its scope chain as an internal [[Scope]] property.
More, since # freezes, there's no need for it to be duplicated, since there is no mutation side channel.
So strawman:arrow_function_syntax proposes freezing and joining, only if the user specifies via the # prefix. Yep, I got it, thanks, though, as mentioned seems it can be managed then at engine level without explicit specifying by the user, no? Do you mean that users shouldn't have to write # prefixes to get joining?
Yeah
That is hard.
Yes, I assumed it though. So from this viewpoint #-funcitons (and actually #-symbol) is just an addition, perhaps even won't be used actively by users. Because I can imagine some tutorials explaining it "don't forget to put # to make a frozen function in case your function is closed over and doesn't contain free variables". It's OK, though I think that before reminding do not forget # in such cases, it will be needed to explain to novice what is a free variable, what is closure, etc. So probably #-functions will not be wide-spread. Although... But, it's just thoughts.
Since semantics of # is moved in respect of function, maybe we can it nevertheless use for records/tuples and for meta-properties of initialiser (Allen's proposal, don't remember why this topic has became silent)?
#record = {x: 10, y: 20}; // without proto #tuple = [1, 2, 3]; // effective dense array
let foo = {x: 10}; let bar = {#proto: foo, y: 20};
SpiderMonkey implements joining for lambdas that do not close over outer lexical variables provided those lambdas are used as the initializer of a property in an object literal, or as the full RHS of assignment to a property of an Object instance. This optimization wins but it requires read and write barriers (which we already have for getters and setters in general). It's complex.
Yes, I know that V8 also does it. I.e. if there are no free variables
and no eval
of course, there's no sense to save [[Scope]]. (JFTR:
Python doesn't save not used free variables even in case of using eval
-- yes, it does deep syntactic analysis of inner/ or parent function and
captures only used bindings in a big single frame, but doesn't form a
scope chain of small frames).
So it's a normal optimization techique today I think.
The # prefix means freeze too, and that is required for joining. ES3 left it to implementations to join but that was a mistake that (if implementations had done so; none did after early SpiderMonkey bugs were fixed) creates a mutation side channel.
Yes.
See also the ES3 global regexp singleton per lexical regular expression bug.
Yeah, I'm aware about it of course.
Dmitry.
On Mon, May 9, 2011 at 6:02 PM, Brendan Eich <brendan at mozilla.com> wrote:
Yes, and we could add call/cc to make (some) compiler writers even happier. But users would shoot off all their toes with this footgun, and some implementors would be hard-pressed to support it. The point is *not * to do any one change that maximizes benefits to some parties while harming others.
By the nature of their task and its complexity, compiler writers targeting JavaScript need JavaScript to have features that make it possible to generate efficient compiled code. Without the big features like call/cc there are many things that just cannot be compiled well enough...which ultimately means all the languages that compile to JavaScript are just thin sugar layers that really aren't even worth the bother. Those languages, like Coffeescript, are obscure and known by only a few people. The goal of pleasing compiler writers should be to make it possible to compile existing languages like Perl, Ruby, Python and Scheme to JavaScript. These languages are the ones that people know and really want to use and target their compilers to JavaScript.
Peter
On May 16, 2011, at 7:55 PM, Peter Michaux wrote:
On Mon, May 9, 2011 at 6:02 PM, Brendan Eich <brendan at mozilla.com> wrote:
Yes, and we could add call/cc to make (some) compiler writers even happier. But users would shoot off all their toes with this footgun, and some implementors would be hard-pressed to support it. The point is *not * to do any one change that maximizes benefits to some parties while harming others.
By the nature of their task and its complexity, compiler writers targeting JavaScript need JavaScript to have features that make it possible to generate efficient compiled code. Without the big features like call/cc there are many things that just cannot be compiled well enough...which ultimately means all the languages that compile to JavaScript are just thin sugar layers that really aren't even worth the bother. Those languages, like Coffeescript, are obscure and known by only a few people.
Rails 3.1 is obscure and known by only a few people?
Seriously, check your attitude. There are many languages in the world. Asserting that Python implemented via Skulpt is not "worth the bother" is insulting to people working on that project and using it. If you don't think it's worth the bother, feel free not to bother. Your opinion does not become an imperative to add arbitrary compiler-target wishlist items.
Here's a list of languages that compile to JS:
jashkenas/coffee-script/wiki/List-of-languages-that-compile-to-JS
I'm sure it's not complete.
The goal of pleasing compiler writers should be to make it possible to compile existing languages like Perl, Ruby, Python and Scheme to JavaScript. These languages are the ones that people know and really want to use and target their compilers to JavaScript.
This is not a straight-up discussion. You ignore safety, never mind usability. Compiler writers want unsafe interfaces to machine-level abstractions. Should we expose them? Certainly not, even though not exposing them hurts efforts to compile (not transpile, as you note) other languages to JS.
Too bad -- the first order of business is JS as a source language. Being a better target for compilers is secondary. It is among the goals, but not super-ordinate.
Compiler-writers don't seem to be having such a bad time of it, and we can proceed on a more concrete requirements proposal basis than taking absolute-sounding philosophical stances.
On May 17, 2011, at 4:57, Peter Michaux <petermichaux at gmail.com> wrote:
The goal of pleasing compiler writers should be to make it possible to compile existing languages like Perl, Ruby, Python and Scheme to JavaScript. These languages are the ones that people know and really want to use and target their compilers to JavaScript.
You sound like you really hate JavaScript and can’t imagine working with it unless some other language is compiled to it.
I’ve programmed quite a bit of Perl, Python, and Scheme and found that once you get to know the proverbial “good parts” of JavaScript, it can be quite elegant. That is, I don’t miss either of these three languages, except maybe for Python’s runtime library (and Java’s tools, but that’s a different topic).
With the increasing momentum behind JavaScript, IMHO the primary goal should be to improve the language for people who actually want to program in it. This is difficult enough, given all the parties that have to be pleased. Listening to feedback from compiler writers should be a secondary goal.
On Tue, May 17, 2011 at 10:50 AM, Axel Rauschmayer <axel at rauschma.de> wrote:
On May 17, 2011, at 4:57, Peter Michaux <petermichaux at gmail.com> wrote:
The goal of pleasing compiler writers should be to make it possible to compile existing languages like Perl, Ruby, Python and Scheme to JavaScript. These languages are the ones that people know and really want to use and target their compilers to JavaScript.
You sound like you really hate JavaScript and can’t imagine working with it unless some other language is compiled to it.
Actually the opposite is true. I write in JavaScript all day and like it a lot. I wouldn't want to compile to JavaScript with today's possibility.
What I was trying to express is that I believe dream of people who want to compile to JavaScript is to write in their server-side language of choice (e.g. Perl, Python, Ruby, Scheme, Java, etc) and compile that to JavaScript.
Peter
Regarding the -> and => syntax, I just want to throw out one other concern
that I hope is taken into account, not only now, but for the future: I
really hope that we don't get to the point where we start adding
functionality to that style of function that is not available to explicit
functions (we're almost, but not, there with having => do the magical this
binding).
I know Brendan and others have declared it's "shorthand only", but it can be a slippery slope, and to rely on the "if you don't like -> don't use it"
argument, we have to make sure that it really stays only a shorthand and nothing more, otherwise it's tail-wagging-the-dog.
In other words, I hope that those who favor -> aren't also hoping that
eventually -> replaces function
entirely. As stated many times thus far in
this thread, there are still those of us who favor (and maybe always will)
the explicitness of function(){}
or #(){}
.
I'm not saying I think this is likely, I just wanted to make sure I was explicit in registering that concern for posterity sake.
On May 17, 2011, at 5:04 PM, Kyle Simpson wrote:
Regarding the -> and => syntax, I just want to throw out one other concern that I hope is taken into account, not only now, but for the future: I really hope that we don't get to the point where we start adding functionality to that style of function that is not available to explicit functions (we're almost, but not, there with having => do the magical
this
binding).
You have to distinguish syntax from semantics.
There's nothing proposed for arrow functions that is more than "shorter syntax" -- including |this| binding.
I know Brendan and others have declared it's "shorthand only", but it can be a slippery slope, and to rely on the "if you don't like -> don't use it" argument, we have to make sure that it really stays only a shorthand and nothing more, otherwise it's tail-wagging-the-dog.
Agreed, which is why I'm still going to write up a fairy radical Ruby-block proposal that competes in this sense: it too gives "better function syntax", plus semantics not available to arrow functions as constrained to be "just syntax".
I hope we'll be able to decide between these two approaches quickly, since I do not want to "do both". That is, either arrow functions win and shorter syntax is enough; or we have blocks for control abstraction (which means other syntax changes, details soon) and no arrow functions.
In other words, I hope that those who favor -> aren't also hoping that eventually -> replaces
function
entirely. As stated many times thus far in this thread, there are still those of us who favor (and maybe always will) the explicitness offunction(){}
or#(){}
.
There's no way to remove 'function' long syntax from JS. Just no way.
Your point about "just syntax" is well-taken, since translation tools will be important in aiding Harmony migration -- not just for targeting downrev browsers but for added static checking -- and these should be as simple (local rewriting, e.g. transpilers not compilers) as possible.
Ok, final and most delicate part of the mission here: allow (v) -> {k: v} and even -> {} to return objects, not make useless block statements. .. Thanks to Doug for pushing on this idea. I believe that it is sound (still to be formalized and tested mechanically) in a bottom-up parser.
The top-down approach by default is to parse a cover grammar until an unambiguous decision point is reached, then depending on the decision, rewrite the AST (e.g., to make a labeled statement in a block instead of an object initializer).
A somewhat less intrusive way to disambiguate blocks/objects might be to separate labels from identifiers - keep the old labels for backward compatibility, but add labels starting with, say ':' (just to pick a prefix).
Then, new syntax, such as arrow functions, could default to assuming objects when they see '{ identifier: .. }', while programmers could write '{ :identifier: .. }' if they want a block starting with a label instead. Disambiguation would not have to look far ahead and there would be less grammar duplication, which might translate into reduced potential for things going wrong. Empty block values are far from useless, but should be possible as '->{;}' or '->{:empty:;}'.
I would still prefer combining the infix arrow with a prefix marker, to avoid ambiguities (for human readers and non-human parsers), some of which might only arise in combinations with future features.
Claus
On Wed, 11 May 2011 02:44:30 +0200, Brendan Eich <brendan at mozilla.com>
wrote:
I've mooted \ along with ƒ, etc. for a while. \ is bad for readability
because it's visually light, but worse, if we want named function
expression shorthand, then \u10A0(){} is a valid
Unicode-identifier-char-named function expression.
Is there a plan to make arrow notation allow named function expressions?
On May 19, 2011, at 2:42 AM, Lasse Reichstein wrote:
Hi Lasse.
On Wed, 11 May 2011 02:44:30 +0200, Brendan Eich <brendan at mozilla.com> wrote:
I've mooted \ along with ƒ, etc. for a while. \ is bad for readability because it's visually light, but worse, if we want named function expression shorthand, then \u10A0(){} is a valid Unicode-identifier-char-named function expression.
Is there a plan to make arrow notation allow named function expressions?
Not in the strawman. Without a leading special character, that's a bridge too far.
Even now the ambiguity with comma expression requires a cover-grammar parsing hack, which is used for destructuring assignment and even (going back to ES1) left-hand side of assignment. This hack is done for assignments, doable for destructuring (SpiderMonkey and Rhino do it), and controversial for arrow function formal parameter vs. comma expression parsing.
On May 19, 2011, at 1:46 AM, Claus Reinke wrote:
Ok, final and most delicate part of the mission here: allow (v) -> {k: v} and even -> {} to return objects, not make useless block statements. .. Thanks to Doug for pushing on this idea. I believe that it is sound (still to be formalized and tested mechanically) in a bottom-up parser. The top-down approach by default is to parse a cover grammar until an unambiguous decision point is reached, then depending on the decision, rewrite the AST (e.g., to make a labeled statement in a block instead of an object initializer).
A somewhat less intrusive way to disambiguate blocks/objects might be to separate labels from identifiers - keep the old labels for backward compatibility,
Why do we need the old useless (unusable, literally) labels for backward compatibility?
Yes, stray labels creep into JS. Typically you find javascript: at the front of scripts. But finding and fixing these is a one time migration step caught by an early error.
but add labels starting with, say ':' (just to pick a prefix).
We really don't want two label syntaxes, especially if there is no strong compatibility argument for stray labels, and they can be detected as early errors in Harmony.
The block vs. object literal disambiguation part of the proposal is at least as solid as the leading formal parameter list, which parses as a comma expression until you get to the arrow. Indeed TC39 may want the label restriction and block vs. object literal part pulled out -- we shall see.
So I say: stray label compatibility is a non-issue and we should focus on the harder nut to crack (the leading parenthesized parameter list).
The top-down approach by default is to parse a cover grammar until an unambiguous decision point is reached, then depending on the decision, rewrite the AST (e.g., to make a labeled statement in a block instead of an object initializer).
A somewhat less intrusive way to disambiguate blocks/objects might be to separate labels from identifiers - keep the old labels for backward compatibility,
Why do we need the old useless (unusable, literally) labels for backward compatibility?
Yes, stray labels creep into JS. Typically you find javascript: at the front of scripts. But finding and fixing these is a one time migration step caught by an early error.
I don't understand how these comments relate to my suggestion, so let me try to clarify what I was suggesting, and why:
-
the grammars for block and objects share common prefixes, leading to ambiguities that can be resolved by lookahead
-
your proposal suggests parsing a cover grammar until disambiguation, plus restrictions to LabelledStatement
-
both LabelledStatement and PropertyAssignment permit IdentifierName followed by ':', followed by something, so disambiguation has to be in the something following the ':', where overlaps like ExpressionStatement further extend the ambiguity
My suggestion was simply to remove IdentifierName from one of the two, by prefixing labels, thereby moving the disambiguation point forward. By my estimate, that should reduce the range of lookahead, the size of cover grammars, and the need for restricted grammars.
I don't know what that has to do with stray labels, and it is obviously not possible to remove the old label syntax immediately. But it would be possible to disambiguate conflicts between property names and block labels in favour of property names.
but add labels starting with, say ':' (just to pick a prefix).
We really don't want two label syntaxes, ..
Right. The old syntax could be deprecated (when opting in for ES/next) - it also doesn't allow label parameters or label variables.
The block vs. object literal disambiguation part of the proposal is at least as solid as the leading formal parameter list, which parses as a comma expression until you get to the arrow. Indeed TC39 may want the label restriction and block vs. object literal part pulled out -- we shall see.
I'm not trying to decide whether the proposal's version is solid, but it is a non-trivial change, and I've seen non-trivial suggestions shot down because they were thought to be risky. The more options there are for dealing with the object literals vs blocks ambiguity, the better the chances for it actually happening. Also, special-casing labelled statements increases the complexity of the grammar.
As a third, extreme option, one could disambiguate by always preferring the object literal interpretation, and ask programmers to start blocks in otherwise ambiguous contexts with an empty statement ('{; ..}' cannot be an object literal). That would require the fewest changes, and perhaps it is all we need, but I'm not sure how well it would work in practice, with existing code.
we should focus on the harder nut to crack (the leading parenthesized parameter list).
Isn't that an example of issues that would not exist if arrow functions had a prefix marker?
Claus
On May 20, 2011, at 7:07 AM, Claus Reinke wrote:
The top-down approach by default is to parse a cover grammar until an unambiguous decision point is reached, then depending on the decision, rewrite the AST (e.g., to make a labeled statement in a block instead of an object initializer). A somewhat less intrusive way to disambiguate blocks/objects might be to separate labels from identifiers - keep the old labels for backward compatibility, Why do we need the old useless (unusable, literally) labels for backward compatibility? Yes, stray labels creep into JS. Typically you find javascript: at the front of scripts. But finding and fixing these is a one time migration step caught by an early error.
I don't understand how these comments relate to my suggestion,
Because the LabelledStatement changes in strawman:arrow_function_syntax restrict labels to prefix only LabelUsingStatements. I was addressing the backward incompatibility here: ES1-5 allow useless labels. You seemed to think that incompatibility was important enough to require new label syntax, but I argued that it is (a) not important; (b) caught by early error during migration.
so let me try to clarify what I was suggesting, and why:
- the grammars for block and objects share common prefixes, leading to ambiguities that can be resolved by lookahead
Only by arbitrarily long lookahead, alas.
- your proposal suggests parsing a cover grammar until disambiguation, plus restrictions to LabelledStatement
I'm still working on the proposal. Cover grammar doesn't quite do the trick, in the formalism we want. We don't want always to parse a MaybeBlockOrObjectLiteral and handle the difference once we see a label on a label-using-statement, or else a property name labeling an expression, by semantics in the prose. We need a proper grammar for blocks and object literals.
- both LabelledStatement and PropertyAssignment permit IdentifierName followed by ':', followed by something,
(LabelledStatement begins with Identifier, not IdentifierName. That only complicates things a bit more ;-), but seems worth pointing out.)
so disambiguation has to be in the something following the ':', where overlaps like ExpressionStatement further extend the ambiguity
No, ExpressionStatement cannot be a LabelUsingStatement.
To be concrete, the problem is {L1:{L2:{L3:{L4:{....LN: XYZZY .... where XYZZY is neither of the form Identifier : nor {. Ignoring syntax errors, if XYZZY is a reserved identifier, it must begin a LabelUsingStatement (or syntax error, in the proposal). Otherwise, it must begin an InitialValue giving LN's property value.
My suggestion was simply to remove IdentifierName from one of the two, by prefixing labels, thereby moving the disambiguation point forward.
I understood your proposal but perhaps I misunderstood that part of the motivation seemed to be stray-label backward compatibility.
By my estimate, that should reduce the range of lookahead, the size of cover grammars, and the need for restricted grammars.
Indeed, just not sure anyone is up for an incompatible new label syntax. It may be the least evil, though!
Labels are not much used intentionally in JS (for break and continue to label, which came in only in ES3).
I don't know what that has to do with stray labels, and it is obviously not possible to remove the old label syntax immediately.
Now I don't see any solution in adding new label syntax. Having to parse the old one leaves us with the ambiguity. What am I missing?
But it would be possible to disambiguate conflicts between property names and block labels in favour of property names.
Being able to disambiguate != having an unambiguous grammar, unfortunately. Unless Harmony bans old label syntax, this doesn't help us write a spec-grammar.
but add labels starting with, say ':' (just to pick a prefix). We really don't want two label syntaxes, ..
Right. The old syntax could be deprecated (when opting in for ES/next) - it also doesn't allow label parameters or label variables.
Do you mean prohibited or deprecated? Usually deprecation means a warning, obsolescence or prohibition means removal.
The block vs. object literal disambiguation part of the proposal is at least as solid as the leading formal parameter list, which parses as a comma expression until you get to the arrow. Indeed TC39 may want the label restriction and block vs. object literal part pulled out -- we shall see.
I'm not trying to decide whether the proposal's version is solid, but it is a non-trivial change, and I've seen non-trivial suggestions shot down because they were thought to be risky. The more options there are for dealing with the object literals vs blocks ambiguity, the better the chances for it actually happening. Also, special-casing labelled statements increases the complexity of the grammar.
Truly, I'm living on the edge here. More work to do, but this is a non-trivial syntactic change. Paren-free is a walk in the park. Still may be worth it, but more work needed. Thanks for the comments.
As a third, extreme option, one could disambiguate by always preferring the object literal interpretation, and ask programmers to start blocks in otherwise ambiguous contexts with an empty statement ('{; ..}' cannot be an object literal). That would require the fewest changes, and perhaps it is all we need, but I'm not sure how well it would work in practice, with existing code.
That is simpler, but I believe I have seen code like this:
L: { S1; S2; S3; } where S2 is a label-using statement, specifically a break from the outer block, a sugared downward goto that skips S3.
Probably only in tests for labels!
Yes, the strawman proposes to break such code. So requiring {; or similar would be a simpler change and non-breaking in the sense that one can rescue such code so it works in Harmony as it used to, by adding one character. Good idea!
we should focus on the harder nut to crack (the leading parenthesized parameter list).
Isn't that an example of issues that would not exist if arrow functions had a prefix marker?
Yes, but then why have arrows (at least why mandate them) at all?
On May 20, 2011, at 7:43 AM, Brendan Eich wrote:
That is simpler, but I believe I have seen code like this:
L: { S1; S2; S3; } where S2 is a label-using statement, specifically a break from the outer block, a sugared downward goto that skips S3.
Probably only in tests for labels!
Yes, the strawman proposes to break such code.
Oops, I'm wrong (pre-caffeine here, sorry!) -- the strawman has NonEmptyBlock as a LabelUsingStatement, so does not break this at all.
So requiring {; or similar would be a simpler change and non-breaking in the sense that one can rescue such code so it works in Harmony as it used to, by adding one character. Good idea!
Your idea still may help make a single spec-grammar that does not require some arbitrary-lookahead decision procedure on the side.
On May 20, 2011, at 7:07 AM, Claus Reinke wrote:
we should focus on the harder nut to crack (the leading parenthesized parameter list).
Isn't that an example of issues that would not exist if arrow functions had a prefix marker?
It is a deeper issue. ECMA-262 currently covers left-hand side of assignment with LeftHandSideExpression, but that produces 42, not a valid LHS. Semantic checks and mandatory errors in spec prose make up for the lack of a precise grammar.
ES5, Clause 16, has
"Attempts to call PutValue on any value for which an early determination can be made that the value is not a Reference (for example, executing the assignment statement 3=4)."
Destructuring assignment -- not the binding forms, e.g. let {x, y} = obj; but just assignment expressions, {x, y} = obj -- takes advantage of this cover grammar approach, but it will require semantic checks. And as Waldemar points out, this constrains RHS "structuring" via object and array initialisers to have the same syntax (unless we add more semantic post-grammar restrictions there too!) as the LHS destructuring patterns.
This may be a bad constraint. Type guards don't seem like they'll be only LHS or RHS, indeed the :: choice for guard prefix was based on easy composing of guards after property names in object initialisers. But some future extension might want LHS and RHS to diverge.
Arrow functions really do want a different ArrorFormalParameters sub-grammar from ( Expression ) where Expression is of course a comma-expression.
So I'm investigating GLR parsing. It can handle all of these cases without ambiguity. It does not require implementatoins to have forking parsers, but it is an attractive spec tool. More on this in a bit.
On May 20, 2011, at 11:06 AM, Brendan Eich wrote:
Destructuring assignment -- not the binding forms, e.g. let {x, y} = obj; but just assignment expressions, {x, y} = obj -- takes advantage of this cover grammar approach,
The example {x, y} assumes strawman:object_initialiser_shorthand makes it to Harmony.
Some references to parsers that do not share ambiguity problems due to limited lookahead such as GLR and PEG parsers.
www.cs.nyu.edu/rgrimm/papers/pldi06.pdf
On May 20, 2011, at 11:26 AM, Kam Kasravi wrote:
Some references to parsers that do not share ambiguity problems due to limited lookahead such as GLR and PEG parsers.
www.cs.nyu.edu/rgrimm/papers/pldi06.pdf, www.cs.rit.edu/~ats/projects/jsm/paper.xml, www.cs.ucla.edu/~awarth/papers/dls07.pdf
The trick is not so much to use an expensive memoizing parser, or even a forking one that could be much more efficient, but to figure out how real JS parsers, which are all top down in the big VMs, should implement. Working on that...
For a presumed-done area, there has been a lot of activity in parser research recently, partially fueled by IDEs and DSLs (model-driven development with good generated tool support).
For grammar spec purposes, it might be interesting to look at self-applications of these techniques (IDEs for parser development, with support for grammar analysis and debugging). I keep meaning to look at ANTLRWorks:
The ANTLR GUI Development Environment
http://www.antlr.org/works/index.html
Anyway, the titles for two of those three urls, for those who don't have time to look right now:
Better Extensibility through Modular Syntax
Robert Grimm
Monadic Parsing using JavaScript
Axel T. Schreiner
Independent of parsing, I recommend that readers of this thread scroll down to the interpreter (search for 'eval'). It gives an example of how an essential programming pattern (monads) is technically supported in Javascript, but mostly useless due to syntactic overhead: instead of bringing out the essential aspects, they get burried in syntax (and if one tries to shunt the 'return's out of the way, ASI says hello).
Javascript coders, when faced with this issue, tend to split into two groups: one that abandons the variable binding functionality of monads and makes due with libraries, and one that writes preprocessors (the author here, also streamline.js and Jscex as just two recent examples from the nodejs list).
Just as a further example for those still unconvinced by the case for better function syntax: it isn't sufficient, but it is necessary!-)
404 for me?
Claus
Thanks Claus for the synopsis and pointing out the 404. ometa is the last paper: www.tinlizzie.org/~awarth/papers/dls07.pdf, which is a javascript packrat parser. Tom and Mark are very familiar with this work I believe. There are some great examples of javascript monads or monad-like frameworks - for example jquery ...
It's unfortunate the harmony grammar cannot take advantage of these more recent advances in parsing, however I understand Brendan's point about accommodating the major implementors. Any transpiler could certainly go this route.
On May 20, 2011, at 2:11 PM, Claus Reinke wrote:
Just as a further example for those still unconvinced by the case for better function syntax: it isn't sufficient, but it is necessary!-)
Good example. Shows how shorter syntax to avoid the 8-letter 'function' is not enough, 'return' elimination via expression-language completion value or something like it is needed too.
Because the LabelledStatement changes in strawman:arrow_function_syntax restrict labels to prefix only LabelUsingStatements. I was addressing the backward incompatibility here: ES1-5 allow useless labels. You seemed to think that incompatibility was important enough to require new label syntax, but I argued that it is (a) not important; (b) caught by early error during migration.
Ok, so you want to restrict label use. But syntax alone cannot guarantee that a given label prefix is ever actually used, it can only rule out alternatives that cannot possibly use the label. And introducing such syntactic restrictions on label use means that one can no longer insert labels without thinking about whether they can be used because inserting unused labels might require rewriting the code. In any case, the result is that both parser writers and developers have to think about the restrictions that make labeled Statements different from Statements.
I still have a few blind spots where things that I thought about for this class of language are not actually permitted by the Javascript grammar, so perhaps LabelUsingStatement won't introduce enough additional complexity to worry about. But, generally speaking, I'd prefer to remove complexity from the grammar, rather than add it.
It isn't that I like labels, but if labels are permitted, I prefer them not introducing additional complexity that I have to think about. So my comments were based on not having the LabelledStatement changes, addressing the ambiguity in another way.
Without changes, any grammar that has ObjectLiteral and Block as alternatives is ambiguous:
ObjectLiteral | Block // ambiguous
Assuming we want to resolve ambiguities by preferring ObjectLiteral, we could write
ObjectLiteral | (Block butnot ObjectLiteral)
where the right branch is the implicit grammar for what you are aiming to spec explicitly, by removing the ambiguous cases from Block, specifically from LabelledStatement, to give us some form of RestrictedBlock that doesn't conflict with ObjectLiteral. So we can combine both in arrow bodies
ObjectLiteral | RestrictedBlock
(PEG-style grammars could make that even more implicit, via ordered choice: anything that is a valid ObjectLiteral can no longer reach the second alternative)
The problem I have with that is that I need to think far ahead to figure out whether I'm writing an ObjectLiteral or a RestrictedBlock and that I need to be aware of whether the Statement I'm writing follows a label or not.
So I'm looking for a way to introduce a committed choice based on limited lookahead instead. It seems that the IdentifierName (PropertyName) vs Identifier (label) case is the one that can lead to long lookaheads, so breaking that seems a step forward. Hence the new-style labels.
It is not necessary to remove old-style labels right away, because old code that uses them only uses old language constructs (which never mix ObjectLiteral and Block). For code that opts into Harmony, a deprecation warning for old-style label seems appropriate, but we don't need to force code rewrites of old code.
For any new language constructs that do mix ObjectLiteral and Block, such as arrow syntax, we can arrange that '{ Identifier : .. }' always defaults to ObjectLiteral, no matter what comes next. In these positions, old-style labels are useless, but new language constructs are only used in new code, so we can ask developers to use new label syntax if they want a Block starting with a label in such positions.
In grammar terms, the arbitrary lookahead alternative
ObjectLiteral | (Block butnot ObjectLiteral)
turns into something like
ObjectLiteral | (Block butnot ('{' (Identifier|StringLiteral) ':' .*)
If this works out, parsers and programmers can commit to one of the alternatives after a limited lookahead, no matter what comes next. Committed choice also means no backtracking, so '{ empty: ; }' would be an invalid ObjectLiteral, not a valid Block, if used as an arrow body (while '{ :empty: ; }' would be an empty block).
So there are pros and cons - the means of disambiguation are easier to understand, but not as expressive.
Now I don't see any solution in adding new label syntax. Having to parse the old one leaves us with the ambiguity. What am I missing?
Old labels in old code don't use new features, like arrow syntax, so the ambiguity does not surface. Old labels in new code using arrow syntax will be overlapped by object property names, so the ambiguity is resolved. New labels in new code using arrow syntax allow to override the default ambiguity resolution.
but add labels starting with, say ':' (just to pick a prefix). We really don't want two label syntaxes, ..
Right. The old syntax could be deprecated (when opting in for ES/next) - it also doesn't allow label parameters or label variables.
Do you mean prohibited or deprecated? Usually deprecation means a warning, obsolescence or prohibition means removal.
Deprecation, with removal not before ES/next/next.
Of course, changing label syntax might give the impression that labels are an encouraged feature, which isn't quite right.
Yes, the strawman proposes to break such code. So requiring {; or similar would be a simpler change and non-breaking in the sense that one can rescue such code so it works in Harmony as it used to, by adding one character. Good idea!
Thanks.
Claus
On May 22, 2011, at 2:01 AM, Claus Reinke wrote:
Because the LabelledStatement changes in strawman:arrow_function_syntax restrict labels to prefix only LabelUsingStatements. I was addressing the backward incompatibility here: ES1-5 allow useless labels. You seemed to think that incompatibility was important enough to require new label syntax, but I argued that it is (a) not important; (b) caught by early error during migration.
Ok, so you want to restrict label use. But syntax alone cannot guarantee that a given label prefix is ever actually used, it can only rule out alternatives that cannot possibly use the label.
The purpose is not to restrict labels to prefix statements that might possibly refer to them, for that sake. Misplaced labels are harmless.
The purpose is to parse block and object initialiser in the same context, unambiguously.
Without changes, any grammar that has ObjectLiteral and Block as alternatives is ambiguous:
ObjectLiteral | Block // ambiguous
Not for a GLR parser with the proposed label restriction.
The problem I have with that is that I need to think far ahead to figure out whether I'm writing an ObjectLiteral or a RestrictedBlock and that I need to be aware of whether the Statement I'm writing follows a label or not.
Not a practical problem. Labels are rare anywhere, even more rare immediately after a {, and of course useless if labeling an expression-statement.
So I'm looking for a way to introduce a committed choice based on limited lookahead instead. It seems that the IdentifierName (PropertyName) vs Identifier (label) case is the one that can lead to long lookaheads, so breaking that seems a step forward. Hence the new-style labels.
Please check the rehashing, you said this last time. I understand new style labels as a disambiguating change, but we would have to prohibit old-style labels, and that's not wanted if we can simply use GLR or better (you mentioned PEG).
You seem to acknowledge that a more powerful parser could handle the disambiguation, so why change the worry to one about "I need to think far ahead [when] writing"? That is a shift of argument, and the new argument is not credible: JS authors do not write labels much, and when they write object initialisers, under the proposal they aren't writing labels inside, no way, no how.
If we go this route of allowing block or object initialiser, then the right answer is not to mangle label syntax in Harmony and put some work on JS programmers migrating code into Harmony.
The right answer is for spec-writers (the few, the brave, blah blah) to step up with GLR or better. Provided there's a sound top-down algorithm that implementors can swallow.
I read Brendan's recent article
brendaneich.com/2011/05/my-jsconf-us-presentation
He asked for community members to make their feelings known and the es-discuss list as one of the places to do it.
In his article, Brendan shows a slide with the following content
The Harmony goals
He also discusses the arrow syntax for functions.
If the arrow syntax is only syntactic sugar for the existing function forms then I don't see how it achieves any of the goals he outlined. The only possible category is "be a better language" but the arrow syntax won't make JavaScript a better language for complex applications or libraries in comparison to any other kind of JavaScript code. I would argue that the arrow syntax will make JavaScript a worse language anyway as there are already perfectly good forms using the "function" keyword now. We don't need new syntax and we don't need multiple ways to do the same thing just for the sake 6 characters. Please keep JavaScript simple.
Look at all the complex/subtle edge cases mentioned in the wiki page about arrow function syntax. Do we really want to have that much trickiness added to the language?
strawman:arrow_function_syntax
Brendan later writes the following as part of the discussion about arrow syntax.
"I’ve been talking about better function syntax for a while. function is too long (I wish I’d used fn in 1995 and preempted this issue)."
I'd like to ask when is "function" too long? I never type it thanks to my text editor's features so I know it is not too long for developers with a good editor. It is not a labor to read the word "function" either. It is never sent over the wire because gzip reduces its size so it is not too long from a performance perspective.
Peter