Re: Allen's lambda syntax proposal

2008-12-18 Thread Lex Spoon
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

2008-12-18 Thread Lex Spoon
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

2008-12-17 Thread Lex Spoon
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

2008-12-17 Thread Lex Spoon
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

2008-10-09 Thread Lex Spoon
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

2008-09-03 Thread Lex Spoon
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

2008-09-02 Thread Lex Spoon
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