Re: Allen's lambda syntax proposal
On Wed, Dec 17, 2008 at 9:53 PM, Yuh-Ruey Chen maian...@gmail.com wrote: Lex Spoon wrote: On this list, the = form has so far been dismissed due to parsing concerns. If that's the only reason, let me try and allay that worry and put that horse back in the race. Scala also has a comma operator, but it still manages to parse the = syntax. They way it does it is to initially parse an expression and then, if it sees a =, reinterpret what it has seen so far as a parameter list. It's an unusual parsing strategy, but it works well and the issue is localized. I don't think anyone is suggesting that it would be too difficult to parse for bottom-up parsers. It's just that it makes it difficult for a certain common class of bottom-up parsers, namely the LALR(k) for fixed k parser generators, to parse. Good point. Actually, though, the same sort of approach should still work. The grammar for a = entry would be something like: atomic_expression = atomic_expression Then, the rule that assembles this parse tree into a real AST would analyze the expression on the left and either convert it to a parse tree, or emit a retroactive parse error. I know this initially violates some design sense--it does mine!--because normally a parser rule reuses subexpressions without change. However, in this case it works out well, and so I think the rule of thumb is misleading. This implementation technique should be simple, localized, easy to understand, and as a result robust. Lex ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Semantics and abstract syntax of lambdas
On Wed, Dec 17, 2008 at 9:42 PM, Yuh-Ruey Chen maian...@gmail.com wrote: Unfortunately, { in expression context is taken by the object literal. However, I think {{ would be feasible. That is, if the parser is in the expression context, if it encounters two '{' tokens in a row, it could treat it as you defined above, e.g. val = {{ val x = 1; val y = 2; x + y }} Cool. I will confess this particular syntax will likely invite confusion about when to use { } versus {{ }}, but maybe that's not true, or maybe there is some other light syntax that can be dreamed up. A light syntax for this kind of expression would immediately solve the issue with lambdas that result in expressions. This, in turn, honestly seems important for lambdas to really be convenient to use. (Granted, lambdas being convenient is much less important than having them available at all.) Do you have an explicit syntax in mind? I can turn this around and say that with really convenient lambdas, expressions of the form you discuss would be trivial, e.g. val = fn { val x = 1; val y = 2; x + y }() That's very helpful, though it does seem roundabout. It presupposes that lambdas take multiple statements, of course. I guess I'm saying that the one-expression version of lambda can lead to ultra-tight code when it applies, so it's a pity to give it up. However, with a light syntax for block expressions, the language can make lambda be one-expression but programmers can still easily write multi-statement lambdas. For example: x = x+1 x = {{ var y = x+1; y*2 }} The former is about as tight as can be, while the latter seems fine as a multi-statement syntax. -Lex ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Semantics and abstract syntax of lambdas
On Mon, Dec 8, 2008 at 4:08 AM, Yuh-Ruey Chen maian...@gmail.com wrote: Jon Zeppieri wrote: So, unless people want to expand the expression grammar significantly, I think the expression body is a nonstarter. How feasible would it be to make JS a pure expression language? That is, can the language be modified to allow things like: x = if (a) b; else c; first_test_prop = for (let p in o) if (/^test/.test(p)/) { p; break; } There's a simpler way to expand the expression language dramatically. I'm not sure why so few languages include it, and I'd be curious if it has been considered for Harmony. The technique is to include an expression form which contains a sequence of statements followed by an expression. In Scala, the syntax looks like this: { statement1; statement2; result_expression } So you can do things like: { val x = 1; val y = 2; x+y } The result would be 3. I'm not sure what the best syntax would be for JavaScript, but surely there is room somewhere. A light syntax for this kind of expression would immediately solve the issue with lambdas that result in expressions. This, in turn, honestly seems important for lambdas to really be convenient to use. (Granted, lambdas being convenient is much less important than having them available at all.) There are side benefits to this expression form, too. It means you can much more frequently replace a function call by the function's contents, even when the function appears in an expression-only context. For example, you can more frequently inline the g() in f(g()). This makes programmers more dextrous, because their rewrites can be more localized. Further, it has obvious application for an optimizing compiler such as GWT's -Lex ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Allen's lambda syntax proposal
On Mon, Dec 1, 2008 at 3:19 PM, Allen Wirfs-Brock allen.wirfs-br...@microsoft.com wrote: Just to clarify some speculation, the syntax I proposed ({||}) was solely inspired by Smalltalk and tempered by the parsing realities of a C-like syntax. Any similarities to Ruby constructs are probably examples of parallel evolution under similar environmental pressures. I suspect that designers of other languages with C-like syntax (C# comes to mind with its () = expr lambda syntax) did not have the experience or goal of using closures to create control abstractions (which often requires passing multi-statement closures) and so arrived at a more function-like concise closure syntax. I can share some history for the = form. It's disconcerting that everyone associates it with C#, because they are open about copying the syntax from Scala. Scala's designer, Martin Odersky, most definitely had in mind that people could use functions for control flow, and in fact he treats it as the primary way to do control flow in Scala. I believe Martin got this syntax most directly from ML's fn expressions. He noticed that you don't really need the keyword. The development for ML-Scala-C# actually looks a lot like is happening in ES discussions. Once a function literal syntax is available, people really want to use it, and the syntax is pressured to get shorter and even to get its keyword dropped in favor of symbols. On this list, the = form has so far been dismissed due to parsing concerns. If that's the only reason, let me try and allay that worry and put that horse back in the race. Scala also has a comma operator, but it still manages to parse the = syntax. They way it does it is to initially parse an expression and then, if it sees a =, reinterpret what it has seen so far as a parameter list. It's an unusual parsing strategy, but it works well and the issue is localized. IMHO, x = x+1 really looks like a function literal, so that's the color I'd paint the bike shed. I agree with Allen and others, though, that any version that drops the keyword will make the form more useful in practice. -Lex ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Thu, Oct 9, 2008 at 5:31 PM, Brendan Eich [EMAIL PROTECTED] wrote: JS has break from labeled statement, and continue to labeled loop bottom, a la Java. These look trouble-free to me. Let me know if you see a hard case. Thanks, My question was whether the semantics of break and continue would support the following: while(true) { (function() { if (--x == 0) break; })(); } I honestly don't know, but it shouldn't cause any real trouble to allow it. The implementation would be analogous to that for labeled return. For example, if the appropriate while loop is no longer on the stack, the break would turn into an exception. As my usual disclaimer, I am not closely following the different ES trends including Harmony. I'm only commenting about what could possibly make the language more consistent and orthogonal. -Lex ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: return when desugaring to closures
On Tue, Sep 2, 2008 at 5:48 PM, Garrett Smith [EMAIL PROTECTED] wrote: On Tue, Sep 2, 2008 at 2:16 PM, Lex Spoon [EMAIL PROTECTED] wrote: On Sun, Aug 24, 2008 at 3:17 AM, Brendan Eich [EMAIL PROTECTED] wrote: First, let's settle the hash over whether any desugaring without extensions such as return-to-label, reformed lexical scope, tamed this, banished arguments, etc. etc., trumps adding a new binding form, to wit: let as block scoped var. With no extensions, it is true, return would end up returning from a different method under the proposed rewrite. Likewise, this and arguments would cause trouble. Possibly break and continue would, depending on what their precise semantics are. Wouldn't any Completion Type cause problems? (function() { throw Error(help.); })(); ? Wouldn't the caller, stack, et c, be all messed up? That sounds like a good rule. At a glance, though, I don't see an immediate problem with throw. In your example, the first thing that happens is the top-most stack level is popped (because there is no exception handler), and then you're back at the original stack level and will start popping from there. So it looks like you get the same behavior whether or not you add a function wrapper and immediately call it. If you did introduce an exception handler, that would be a different story. But introducing an exception handler would be a separate step from introducing the function wrapper. The function wrapper itself wouldn't, as far as I can see, cause trouble for throw and catch. By the way, the above rewrite is precisely the one I am thinking it would be nice to make available to programmers. It doesn't work out of the box, but with labeled return, and with the proper interpretation of break and continue, it would work with the only burden being to label the returns. That's a local change that would not require rethinking the rest of the algorithm. However, they work under some specific extensions that appear to benefit JavaScript anyway. I suspect that most languages with both return expressions and nested functions will eventually want a way to return from other than the innermost function. More generally, it would be really nice if programmers could safely add a nested function without losing access to important things from their surrounding scope. That goes not just for return, but also arguments, this, break, and continue. Those are not lost if you store them in a variable in the containing scope. True. It's mostly return that is in trouble. You could work around arguments and this by making new variables to refer to them. Finally, there was a little bit of question about what the semantics would be. Let me go into just a little more detail. The idea is that instead of just return foo, you could also put a label on the return. What would you use that for? I earlier described why you would want it in principle: if you have both return and nested functions, you otherwise are hampered in using them both at the same time. Further, there is no reason to believe that using one means you won't want to use the other. Their purposes are orthogonal, so you would think there would be code that wants to do both. As a specific example, consider the style of collection library where each collection type supplies methods for looping through the collection, searching for items, etc. For example, suppose all of the collections in the library implement a foreach() method that goes through the elements of the collection. It's true that many people don't like this style of library, but many people do, and those people I would bet overlap heavily with those who like having nested functions at all. (I freely grant that if you hate nested functions, this whole discussion is unexciting, because your answer will always be, well don't nest functions--problem solved!) Given such a library, you could implement a find() method by calling foreach(). The contract of find() is to take a predicate as argument (itself a function), apply that predicate to each element of a supplied collection, and then return the matching item that is found. If no matching item is found it returns null. Here's how it looks if you have return from outer function: function find(collection, predicate) { collection.foreach(function (each) { if (predicate(each)) return:find each; } return null; } So that's one example where you want both nested functions and return from outer function in the same place. There are lots of other collection operations, too. Further, there are lots of libraries other than collection libraries that can benefit from implementing control-structure-like methods such as foreach. This whole style of library, one of the major benefits of nested functions, is in trouble if you don't have return from outer function. To back up, this is all just a general comment. As far as I can tell, the feature is sound and would be helpful
Re: return when desugaring to closures
On Sun, Aug 24, 2008 at 3:17 AM, Brendan Eich [EMAIL PROTECTED] wrote: First, let's settle the hash over whether any desugaring without extensions such as return-to-label, reformed lexical scope, tamed this, banished arguments, etc. etc., trumps adding a new binding form, to wit: let as block scoped var. With no extensions, it is true, return would end up returning from a different method under the proposed rewrite. Likewise, this and arguments would cause trouble. Possibly break and continue would, depending on what their precise semantics are. However, they work under some specific extensions that appear to benefit JavaScript anyway. I suspect that most languages with both return expressions and nested functions will eventually want a way to return from other than the innermost function. More generally, it would be really nice if programmers could safely add a nested function without losing access to important things from their surrounding scope. That goes not just for return, but also arguments, this, break, and continue. It's an orthoganality problem. With JavaScript's current limited return expression, programmers have trouble when they try to use both function nesting and return at the same time. Using one feature makes it harder to use the other. That's a philosophical argument, and so people will disagree. That's why I tried to pull in experience with existing languages that have both of these features. Not all that many do, actually. The languages that push nested functions the hardest are functional languages, and most of them do not have return. Of those that have both, though, it's notable that most also have non-local return. I earlier listed Scala, Smalltalk, and Lisp as examples. On the flip side, I can only think of two languages: Java (counting anonymous inner classes as nested functions) and X10 (which is based closely on Java). Can anyone else think of other language experiences to compare against? Looking at this experience, it's fair to say that non-local return works out fine in practice. Further, the two languages in my list do not have this feature, also make it annoying to write nested functions that also want to return. I guess it's a matter of taste, but I have to say that Java (and X10), despite their many other advantages, don't make it concise nor elegant to nest anonymous classes very much. Java's designers seem to agree, having written their collections library not to support a style where you'd use a lot of nested anonymous classes. Stepping back, let me emphasize that I'm not religious about desugaring as a definition approach. I'm more concerned that an intuitive-looking rewrite doesn't work. Programmers are going to do intuitive-seeming things to their code, and it's a nicer language when those intuitive-seeming things are in fact safe. Of course, if it can't be done, it can't be done, and the wart has to stay. In this case, though, the wart can be removed by adding a feature that has merits of its own. Thus, I don't know what the Harmony process is, but I would recommend a careful look at accessing return, this, and arguments for functions surrounding the immediately enclosing function. If those work out as well as they appear to, then programmers would have one less thing to worry about when they introduce nested functions into their programs. Finally, there was a little bit of question about what the semantics would be. Let me go into just a little more detail. The idea is that instead of just return foo, you could also put a label on the return. I don't know what the syntax would be, but as a straw man, maybe it would be return:bar foo. This notation means to return foo from the function named bar. If bar happens to be the immediately enclosing function, then you return exactly as in JavaScript right now. Otherwise, you pop stack frames until you get to the correct bar stack frame. You then return from that one. If that frame has already popped, then the return fails, much like an exception that is never handled. Does that explain it well enough, or should I go on? -Lex ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss