return when desugaring to closures

Lex Spoon spoon at google.com
Wed Sep 3 14:16:08 PDT 2008


On Tue, Sep 2, 2008 at 5:48 PM, Garrett Smith <dhtmlkitchen at gmail.com> wrote:
> On Tue, Sep 2, 2008 at 2:16 PM, Lex Spoon <spoon at google.com> wrote:
>> On Sun, Aug 24, 2008 at 3:17 AM, Brendan Eich <brendan at mozilla.org> 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 in practice.  However, I
don't know what all are the aims of Harmony, nor the timelines, etc.,
and I'm certainly not volunteering to do any of the leg work.  The
language obviously can live without the feature, because it has for
years, and at best it makes programming in Harmony just a little bit
nicer.

-Lex


More information about the Es-discuss mailing list