Lambda vs. function

Dave Herman dherman at ccs.neu.edu
Thu Oct 16 14:39:49 PDT 2008


>> b) creating a clearer place in the language syntax to enforce tail 
>> calling by eliminating `return'
> 
> I don't understand what you mean in point b.

Consider two different syntaxes for a function performing a tail call:

     lambda(x) { f(x) }
     function(x) { return f(x) }

The traditional semantics of `return' is 1) evaluate the argument to get 
a value and 2) jump to the caller (i.e., pop the stack frame) with that 
value. If we try to graft tail calls on top of `return', we reverse the 
semantics: 1) jump to the caller with an unevaluated expression and 2) 
evaluate the subexpression.

But what if the `return' occurs in a try-block? Then popping the whole 
activation frame would be incorrect (it would unwind the exception 
handler too soon). So now we have to say the semantics of `return' 
depends on its context:

     1) if the `return' is in tail position, then
        1.1) jump to the caller and
        1.2) evaluate the subexpression
     2) if the `return' is not in tail position, then
        1.1) evaluate the subexpression and
        1.2) jump to the caller

You could certainly argue that this is just a syntactic difference for 
the same behavior as the `return'-less form. But `return' suggests a 
control effect, and imperative behavior, and we're messing with its 
interpretation.

I claim that `return' suggests that a function call corresponds to an 
activation frame (which is in fact the way ES3 is explicitly specified), 
which is popped after evaluating the argument of a `return' statement. 
By contrast, a procedure form that does not use `return' simply avoids 
any suggestion of control effect, and tail calling is a natural 
interpretation.

To some degree, you could wedge proper tail calling on top of the 
semantics of function/return. But the notion of what constitutes a tail 
position is much clearer with lambda.

> Why isn't function a realistic alternative?  You cited four differences:
> 
> return:  Return from within a function returns from that function 
> instead of doing a longjmp.  I'd consider that to be a feature.

There is no longjmp in ES, nor is longjmp being proposed. Maybe you're 
mixing semantics with implementation. Or maybe you're making fun of the 
return-to-label proposal. I don't see what you're driving at. But 
`return' *is* a transfer of control; it is a jump. It just happens to be 
a jump that you don't have to implement in C with longjmp.

> this:  You have a point there.
> 
> var:  Not an issue if you're not using var inside the lambda.  Code 
> generation that wants to use lambda would use var why?
> 
> arguments:  Again, not an issue if you're not using the arguments 
> array.  If a code generator is updated for lambda, then presumably it 
> will be updated not to use the arguments array.

If you're writing a compiler that targets ES, you can have conventions 
that avoid using those features. But for defining ES language features 
by desugaring, we don't have that luxury; for example:

     let (x = e) { s } !== (function(x) { s })(e)

because `s' may contain any of those four features (this, var, 
arguments, return). This would be a problem for macros, too.

Dave


More information about the Es-discuss mailing list