Re: Simple tail calls
Hi Peter, From what I understand, if lambdas are supposed obey Tenent's principle, then they cannot have a return statement/expression. Wrapping an expression in a lambda must not change the meaning of the program. the following would need to be equivalent. Right, I personally think this is unnecessary; functions don't follow this principle, after all. I think it makes sense for expressions to have the same meaning, but not control flow statements when moved into a new execution context. Cheers, Michael -- Print XML with Prince! http://www.princexml.com ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Basic Lambdas and Explicit Tail Calls Repackaged
Hi, I thought it might be good to package these two proposals together, as they are interrelated. It would be very much appreciated if anyone could point out major use cases that these proposals don't cover, or any other important issues that they might currently neglect. BASIC LAMBDAS Lambdas are similar to functions, but use the lambda keyword instead of function, always have a this value of undefined, and do not have an arguments object in scope. LAMBDA EXAMPLES: var x = lambda(n) { return n + 1 } var x = lambda fact(n) { if (n = 1) return 1; else return n * fact(n-1); }; EXPLICIT TAIL CALLS The JavaScript specification should require implementations to treat any ReturnStatement containing a CallExpression as a tail call, except in cases when the ReturnStatement is within a WithStatement or within a TryStatement. TAIL CALL EXAMPLES: function f() { return g(); // -- tail call! } function f() { g(); // -- not a tail call, no return keyword } function f(x) { with (x) { return g(); // -- not a tail call, inside with } } ADVANTAGE: Very easy to specify and very easy to implement. It does not require tail calls for CallExpressions which occur outside of a ReturnStatement, eliminating a big chunk of specification devoted to figuring out exactly what is or isn't a tail call position. It does not require scanning through a function to identify tail positions, so even the most basic interpreter operating directly on abstract syntax trees could still implement them easily. ADVANTAGE: It makes tail calls explicit. Using return f() is as close as you can get to introducing a new keyword, without introducing a new keyword. It makes it immediately obvious whether a call is a tail call or not. EIBTI. ADVANTAGE: Explicit tail calls preserve correctness. The only point of requiring tail call optimisation rather than leaving it optional is because the correctness of some code depends upon it. However, implicit tail calls are easily lost as code changes. Consider a tail call within a deeply nested block: function f() { if (cond) { if (cond) { ... g(); // -- supposed to be a tail call, but is it? } } minorCleanup(); // -- oh no! someone added this! } If tail calls use an explicit return, it is much harder to accidentally break them, or overlook them. If tail calls are essential to ensure the correctness of some code, they should be explicit in that code. NOTE: Does not preclude fancier optimisations. Implementations would be required to treat return calls as tail calls. However, they would be free to treat other calls as tail calls as well, or perform more complex optimisations such as introducing accumulator arguments to transform code into tail-recursive form. Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Allen's lambda syntax proposal
Peter Michaux wrote: On Sat, Dec 6, 2008 at 7:51 PM, David-Sarah Hopwood [EMAIL PROTECTED] wrote: The keyword 'function' shouldn't be used for this because a lambda is not a function. However, const name(formals) ... let name(formals) ... could be sugar for const name = lambda(formals) ...; Does const have var or let scoping...or is it even a declaration at all? When 'let' and 'const' were proposed to be added to ES3.1, 'const' would have been a declaration with the same scoping as 'let'. This part of the ES3.1 proposal wasn't controversial, I think. Although it is bulky it might be better to write const var and const let. A variable being constant or not is orthogonal to its scoping and should be controlled independently. That would be the case if the scoping of 'let' wasn't a strict improvement on, and intended replacement for, that of 'var'. -- David-Sarah Hopwood ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Allen's lambda syntax proposal
David-Sarah Hopwood wrote: Jon Zeppieri wrote: On Sat, Dec 6, 2008 at 11:49 AM, Maciej Stachowiak [EMAIL PROTECTED] wrote: On Dec 5, 2008, at 11:12 PM, Jon Zeppieri wrote: I don't get it. What issue is raised by return-to-label that isn't already raised by exceptions? [...] Also, what was the performance issue? The (minor) performance issue is that if there is a lambda that returns from a given function, all calls within that function body must check for an escape, even if the lambda is never passed to them or otherwise accessible to them. Similarly for calls within the scope of a labelled statement or iteration that contains a lambda with a corresponding 'break' or 'continue'. Please disregard this -- I had overlooked a way to make the performance of escape continuations identical to that of exceptions. No explicit per-call checks are needed; the jump to the break/continue/return target can be handled using the same mechanism as try/catch handlers, with the same possible optimizations. In the case where the control abstraction is built-in or its implementation is inlined, the performance can be the same as conventional break/continue/return. -- David-Sarah Hopwood ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Allen's lambda syntax proposal
On 2008-12-06, at 00:23EST, David-Sarah Hopwood wrote: P T Withington wrote: Would it work to move the parameter list inside the block (as in the Smalltalk way, but as a regular parameter list, not using ||'s)? {(a, b) a + b} AFAICT, `{(` is a syntax error for an expression in es3. I think this is unambiguous, but I don't like it because it has no symbol or combination of symbols that is specific to a lambda. ( {( can occur as the start of a block.) ^{(a, b) a +b} Perhaps? An expression cannot start with `{(`, a statement cannot start with `^`. ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Basic Lambdas and Explicit Tail Calls Repackaged
Is your lambda proposal competing with http://wiki.ecmascript.org/doku.php?id=strawman:lambdas (gave me by Brendon)? Another question: the only difference between lambda and function is: // pseudo code this = undefined; delete arguments; Why would anybody want to use a lambda instead of a function? 2 characters less to type? What is the compelling reason, the super idea behind the lambda besides confusing programmers, and more things to implement by compiler writers? Thanks, Eugene Michael Day wrote: Hi, I thought it might be good to package these two proposals together, as they are interrelated. It would be very much appreciated if anyone could point out major use cases that these proposals don't cover, or any other important issues that they might currently neglect. BASIC LAMBDAS Lambdas are similar to functions, but use the lambda keyword instead of function, always have a this value of undefined, and do not have an arguments object in scope. LAMBDA EXAMPLES: var x = lambda(n) { return n + 1 } var x = lambda fact(n) { if (n = 1) return 1; else return n * fact(n-1); }; EXPLICIT TAIL CALLS The JavaScript specification should require implementations to treat any ReturnStatement containing a CallExpression as a tail call, except in cases when the ReturnStatement is within a WithStatement or within a TryStatement. TAIL CALL EXAMPLES: function f() { return g(); // -- tail call! } function f() { g(); // -- not a tail call, no return keyword } function f(x) { with (x) { return g(); // -- not a tail call, inside with } } ADVANTAGE: Very easy to specify and very easy to implement. It does not require tail calls for CallExpressions which occur outside of a ReturnStatement, eliminating a big chunk of specification devoted to figuring out exactly what is or isn't a tail call position. It does not require scanning through a function to identify tail positions, so even the most basic interpreter operating directly on abstract syntax trees could still implement them easily. ADVANTAGE: It makes tail calls explicit. Using return f() is as close as you can get to introducing a new keyword, without introducing a new keyword. It makes it immediately obvious whether a call is a tail call or not. EIBTI. ADVANTAGE: Explicit tail calls preserve correctness. The only point of requiring tail call optimisation rather than leaving it optional is because the correctness of some code depends upon it. However, implicit tail calls are easily lost as code changes. Consider a tail call within a deeply nested block: function f() { if (cond) { if (cond) { ... g(); // -- supposed to be a tail call, but is it? } } minorCleanup(); // -- oh no! someone added this! } If tail calls use an explicit return, it is much harder to accidentally break them, or overlook them. If tail calls are essential to ensure the correctness of some code, they should be explicit in that code. NOTE: Does not preclude fancier optimisations. Implementations would be required to treat return calls as tail calls. However, they would be free to treat other calls as tail calls as well, or perform more complex optimisations such as introducing accumulator arguments to transform code into tail-recursive form. Best regards, Michael ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Basic Lambdas and Explicit Tail Calls Repackaged
Hi Eugene, Is your lambda proposal competing with http://wiki.ecmascript.org/doku.php?id=strawman:lambdas (gave me by Brendon)? It is a different proposal, I think it helps to have more than one proposal, in order to clearly see the different trade offs involved. Why would anybody want to use a lambda instead of a function? 2 characters less to type? What is the compelling reason, the super idea behind the lambda besides confusing programmers, and more things to implement by compiler writers? Well, that's a really good question, as lambdas don't sound sufficiently different to regular functions in this proposal to be worth doing. The lambda proposal on the wiki gives the following Why reasons: A simpler primitive underlying the language’s first-class functions. Removing 'this' and 'arguments' also gives a simpler primitive, but is it enough to bother with? Supports defining other features via desugaring without breaking equivalence with implicit features (arguments, this, return) — this is sometimes described as Tennent’s Correspondence Principle [ 1, 2 ]. Not clear what this means, or what benefit it brings to either JavaScript programmers or implementors. A well-tested feature of programming languages since time immemorial. JavaScript already has higher-order functions, and much fewer languages have lambdas where a return returns from the enclosing function. Supports tail calls more naturally than function. I don't see what's unnatural about explicit tail calls in functions. Simple, composable features like lambda are useful for other language features defined via desugaring/compiling other languages to ES/macros What do lambdas in the wiki have that lambdas-as-functions-without-this do not have? They seem to have more complexity, but I can't see how they are significantly more useful. Best regards, Michael -- Print XML with Prince! http://www.princexml.com ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Basic Lambdas and Explicit Tail Calls Repackaged
I agree with you: lambdas in http://wiki.ecmascript.org/doku.php?id=strawman:lambdas look useless too. They don't have a clearly articulated vision nor compelling use cases (at least not in the document). I am for the lambda facility as a short notation for small functional snippets, but both proposals do nothing for this use case. So far it all looks like lambdas are cool --- we can do lambdas too! kind of exercise. Thanks, Eugene Michael Day wrote: Hi Eugene, Is your lambda proposal competing with http://wiki.ecmascript.org/doku.php?id=strawman:lambdas (gave me by Brendon)? It is a different proposal, I think it helps to have more than one proposal, in order to clearly see the different trade offs involved. Why would anybody want to use a lambda instead of a function? 2 characters less to type? What is the compelling reason, the super idea behind the lambda besides confusing programmers, and more things to implement by compiler writers? Well, that's a really good question, as lambdas don't sound sufficiently different to regular functions in this proposal to be worth doing. The lambda proposal on the wiki gives the following Why reasons: A simpler primitive underlying the language’s first-class functions. Removing 'this' and 'arguments' also gives a simpler primitive, but is it enough to bother with? Supports defining other features via desugaring without breaking equivalence with implicit features (arguments, this, return) — this is sometimes described as Tennent’s Correspondence Principle [ 1, 2 ]. Not clear what this means, or what benefit it brings to either JavaScript programmers or implementors. A well-tested feature of programming languages since time immemorial. JavaScript already has higher-order functions, and much fewer languages have lambdas where a return returns from the enclosing function. Supports tail calls more naturally than function. I don't see what's unnatural about explicit tail calls in functions. Simple, composable features like lambda are useful for other language features defined via desugaring/compiling other languages to ES/macros What do lambdas in the wiki have that lambdas-as-functions-without-this do not have? They seem to have more complexity, but I can't see how they are significantly more useful. Best regards, Michael ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Proposal: Modify automatic semicolon insertion in strict mode
Most people on this list consider automatic semicolon insertion something of a mistake. However, I think this feature would be fine if it were not so eager and thus causing all sorts of subtle errors and hampering language evolution (e.g. the ongoing lambda discussion). By eager, I mean that there are too many cases where automatic semicolon insertion takes place. So here's the proposal: 1) Stricter rules for function call and subscript operators ... f (args) ... currently parses as: ... f(args) ...; I propose that this instead parses as: ... f; (args) ...; Likewise, ... a [args] should parse as: ... a; [args] ...; Note that: ... f( args ) ... should still parse as: ... f(args) ...; 2) Stricter rules for binary operators (including '.' and ',') ... a BINARY_OP b currently parses as: ... a BINARY_OP b ...; I propose that this instead parses as: ... a; BINARY_OP b ...; and thus results in a syntax error, unless it's a unary operator. Note that: ... a BINARY_OP b ... should still parse as: ... a BINARY_OP b ...; Since expressions starting with unary operators are usually valid yet erroneous code... 3) All expression statements that start with an expression of lesser precedence than an assignment operator should result in an error, or at the very least, a warning. This applies even if the statement does have an effect. For example, all the following lines should generate some warning: +(a = 10) +func() a * func() [a, b, c] OTOH, if operator overloading is ever added to the language, this will be trickier, since user-defined operator methods may cause side effects. 4) (Optional) To simplify grammar implementation, these new rules apply even if the expressions are nested within group operators, e.g. ... ( ... a BINARY_OP b ... ) ... should still parse as ... ( ... a; BINARY_OP b ... ) ...; and result in a syntax error. Ditto for [], and {}. I believe the official Ruby interpreter works this way and I haven't heard many complaints about it. 5) Since this is all clearly incompatible with existing ES3 code, this requires an opt-in: these new rules should only be followed under strict mode. 6) This is auxiliary to this proposal, but it needs to be stated: There should be a tool that converts ES3 to ES-Harmony in a similar vein to Python's 2to3 tool, that would ease the migration cost of above and other strict mode changes. ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: Modify automatic semicolon insertion in strict mode
Eric Suen wrote: Your proposal make nosense to me, first, I not sure what is your strict mode means, because in strict mode there is no automatic semicolon insertion. in must examples you give there is no automatic semicolon insertion, your proposal make thing even worse, these are just different coding style, for examples, for long expression, it could be: a + b or a + b and a + b if this will cause syntax error, I think no one will use JavaScript... Yes, it will make currently valid coding styles invalid, but that's for the sake of a clean grammar. I modeled my rules off what Ruby allows, and I haven't really heard Ruby authors complaining about those rules. If what you said was true, then Ruby would not be growing in popularity, even if it has a different language genealogy. I can envision two clean options for strict mode: 1) mandating semicolons 2) modifying automatic semicolon insertion along the lines of what I propose I'm fine with either. ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Allen's lambda syntax proposal
Alex Russell wrote: Indeed, it can look like an expression to begin a name assignment: var thinger = {(foo+bar): ... }; Has a syntax like this been shot down yet?: var thinger = {{ foo, bar }: ... }; Since objects (much less literals) aren't used as keys in hashes often, this strikes me as being somewhat less ambiguous. The short (no args) version might then be: var thinger = {: ... }; Arguments against? I think that would require LALR(k) for bottom-up parsers, which we're trying to avoid mandating. ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: Modify automatic semicolon insertion in strict mode
Yuh-Ruey Chen wrote: Most people on this list consider automatic semicolon insertion something of a mistake. However, I think this feature would be fine if it were not so eager and thus causing all sorts of subtle errors and hampering language evolution (e.g. the ongoing lambda discussion). By eager, I mean that there are too many cases where automatic semicolon insertion takes place. There are, but I think it's a bad idea to change semicolon insertion in such a way that currently valid programs are still valid but are parsed differently. So here's the proposal: 1) Stricter rules for function call and subscript operators ... f (args) ... currently parses as: ... f(args) ...; I propose that this instead parses as: ... f; (args) ...; Likewise, ... a [args] should parse as: ... a; [args] ...; Note that: ... f( args ) ... should still parse as: ... f(args) ...; All of these changes affect the behaviour of valid programs without making them invalid. 2) Stricter rules for binary operators (including '.' and ',') ... a BINARY_OP b currently parses as: ... a BINARY_OP b ...; I propose that this instead parses as: ... a; BINARY_OP b ...; and thus results in a syntax error, unless it's a unary operator. Note that: ... a BINARY_OP b ... should still parse as: ... a BINARY_OP b ...; Since expressions starting with unary operators are usually valid yet erroneous code... No, it's perfectly commonplace to break a line before a binary operator: var foo = some_very_long___expression + some_other_expression; 3) All expression statements that start with an expression of lesser precedence than an assignment operator should result in an error, or at the very least, a warning. This applies even if the statement does have an effect. For example, all the following lines should generate some warning: +(a = 10) +func() a * func() [a, b, c] OTOH, if operator overloading is ever added to the language, this will be trickier, since user-defined operator methods may cause side effects. This has more merit than 1) or 2). I considered it for Jacaranda, although it didn't make it into the spec. However, warnings are out of scope for the language specification, unless they are in some informative annex. Also, this proposal doesn't seem to have anything to do with semicolon insertion. 4) (Optional) To simplify grammar implementation, these new rules apply even if the expressions are nested within group operators, [...] 5) Since this is all clearly incompatible with existing ES3 code, this requires an opt-in: these new rules should only be followed under strict mode. That's not sufficient. Strict mode is supposed to be a subset. -- David-Sarah Hopwood ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: Modify automatic semicolon insertion in strict mode
Yuh-Ruey Chen wrote: Eric Suen wrote: Your proposal make nosense to me, first, I not sure what is your strict mode means, because in strict mode there is no automatic semicolon insertion. No, semicolon insertion occurs also in strict mode. Perhaps it shouldn't. in must examples you give there is no automatic semicolon insertion, your proposal make thing even worse, these are just different coding style, for examples, for long expression, it could be: [...] if this will cause syntax error, I think no one will use JavaScript... Yes, it will make currently valid coding styles invalid, but that's for the sake of a clean grammar. I modeled my rules off what Ruby allows, and I haven't really heard Ruby authors complaining about those rules. If what you said was true, then Ruby would not be growing in popularity, even if it has a different language genealogy. That's not a valid argument: Ruby had these rules from the start. -- David-Sarah Hopwood ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Allen's lambda syntax proposal
Alex Russell wrote: On Dec 5, 2008, at 9:23 PM, David-Sarah Hopwood wrote: P T Withington wrote: Would it work to move the parameter list inside the block (as in the Smalltalk way, but as a regular parameter list, not using ||'s)? {(a, b) a + b} AFAICT, `{(` is a syntax error for an expression in es3. I think this is unambiguous, but I don't like it because it has no symbol or combination of symbols that is specific to a lambda. ( {( can occur as the start of a block.) Indeed, it can look like an expression to begin a name assignment: var thinger = {(foo+bar): ... }; No, property names in object literals are required to be a single IdentifierName, StringLiteral or NumericLiteral. Has a syntax like this been shot down yet?: var thinger = {{ foo, bar }: ... }; Since objects (much less literals) aren't used as keys in hashes often, this strikes me as being somewhat less ambiguous. The short (no args) version might then be: var thinger = {: ... }; Arguments against? What is the advantage of this syntax over ^(a, b) {a+b}, for example? Ditto for P T Withington's proposal of ^{(a, b) a+b}. -- David-Sarah Hopwood ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Proposal: Modify automatic semicolon insertion in strict mode
On Dec 7, 2008, at 9:53 PM, David-Sarah Hopwood wrote: Yuh-Ruey Chen wrote: Eric Suen wrote: Your proposal make nosense to me, first, I not sure what is your strict mode means, because in strict mode there is no automatic semicolon insertion. No, semicolon insertion occurs also in strict mode. Perhaps it shouldn't. TC39 already agreed it should, for ES3.1. Strict mode has enough migration-tax that we do not want to risk making it unused in practice due to lack of ASI. It's hard to know what would happen, but the sense of the committee was to leave ASI alone in strict mode in order to make strict mode easier to use in existing code, as well as new code meant to work in old browsers where the author didn't test carefully. Such undertesting happens, just as for quirky HTML -- the XHTML utopia notwithstanding (IE processed text/xhtml using quirky syntax error correction, guaranteeing non-wellformedness to some degree in the deployed content). Missing semicolons happen too, in spite of the best intentions. Never mind that many JS developers would have our heads for removing ASI from strict mode, the problem remains that programmers don't know where they depend on ASI, and if we try to force them to care, we'll fail -- they may not even be around, and the content errors will be foisted on innocent end users of the incumbent content. I was pushing for this agreement, so others should give their own views, but we did in fact reach a decision on this point. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Basic Lambdas and Explicit Tail Calls Repackaged
On Dec 7, 2008, at 1:10 AM, Michael Day wrote: Hi, I thought it might be good to package these two proposals together, as they are interrelated. It would be very much appreciated if anyone could point out major use cases that these proposals don't cover, or any other important issues that they might currently neglect. BASIC LAMBDAS Lambdas are similar to functions, but use the lambda keyword instead of function, always have a this value of undefined, and do not have an arguments object in scope. If the lambda is enclosing in a function, is that function's arguments binding visible in the lambda body? Probably you meant to allow outer arguments to be unshadowed, not somehow censored, but I thought I'd ask. Same question for |this| could be asked (never mind an enclosing function, since |this| is bound in global code), although Mark had an argument against lexical |this| for classes as sugar -- but that argument may not bear on lambdas. LAMBDA EXAMPLES: var x = lambda(n) { return n + 1 } var x = lambda fact(n) { if (n = 1) return 1; else return n * fact(n-1); }; How about var in lambda? Allowed, or banned in favor of let or const? EXPLICIT TAIL CALLS The JavaScript specification should require implementations to treat any ReturnStatement containing a CallExpression as a tail call, except in cases when the ReturnStatement is within a WithStatement or within a TryStatement. The ReturnStatement's Expression (if present) must be a CallExpression, not just contain one, of course. Just picking nits ;-). I like your thinking here, on both lambdas and tail calls. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss