Re: return when desugaring to closures

2008-10-11 Thread David Herman
   if (h == 0)
 h = function() {break};

Did you mean if (x == 0)? That's been confusing me in trying to read your 
example.

Dave
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread Peter Michaux
On Sat, Oct 11, 2008 at 10:02 AM, Mark S. Miller [EMAIL PROTECTED] wrote:
 On Sat, Oct 11, 2008 at 9:11 AM, Peter Michaux [EMAIL PROTECTED] wrote:
 As it stands, I always write the following in ES3

 var f = function() {};

 and now that arguments.callee is on the chopping block, I've started
 writing recursion as the painful contortion below

 var f = (function() {
  var callee = function() { callee(); };
  return callee;
 })();

 I don't get it. Why not write

   var f = function() { f(); };

var f = function() {f();};
var g = f;
f = function(){alert('broke your recursion :)');};
g();

The call to g will not create an infinite loop which is the intended
behavior of the function object defined in the first line. The late
binding of the recursive call to whatever f happens to reference is
the problem.

Peter
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Strengthening Function.prototype.toString

2008-10-11 Thread Eugene Lazutkin
Inline.

Yuh-Ruey Chen wrote:
 
 So as far as I can tell, what we need to discourage usage of
 func.toString() is:
 
 1) An API for function currying/partial evaluation (specializing/binding
 certain arguments).
 2) A read-only property on functions that contains the list of parameter
 names.

Both points are valid. But #2 is of little utility for variadic 
functions. Example:

function foo(){
   return arguments[5];
};

As you can see it is generally impossible to know how many arguments are 
actually expected, and what are their names.

Personally I am not against a read-only property for argument names, 
just pointing out its limited utility.

 For any other purpose, I would think that you might as well parse the
 whole source file rather than just the function, since you would need to
 keep track of closures. For example, consider this:
 
 function foo() {
 var x = 10;
 return function() {
return x;
 };
 }
 
 function bar(f) {
 var x = 20;
 print(f());
 print(eval(f.toString())());
 }
 
 bar(foo());
 
 That would print 10, then 20. So as you can see, even in the same scope,
 eval(f.toString())(...) is not necessarily equal to f(), even if
 f.toString() is a correct decompilation of f.

That's a good point about literal comparison of bodies. The other side 
of this argument is: it is generally impossible to read the function 
body, and compile it back with eval() expecting to get the same 
functional behavior because it this point we have no idea about 
closures. To accomplish that we need a way to manipulate 
closures/context: extract it from a function somehow, specify it as a 
parameter to eval() and so on. I am not sure it is doable/practical.

Thanks,

Eugene
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread David-Sarah Hopwood
Peter Michaux wrote:
 On Sat, Oct 11, 2008 at 10:02 AM, Mark S. Miller [EMAIL PROTECTED] wrote:
 On Sat, Oct 11, 2008 at 9:11 AM, Peter Michaux [EMAIL PROTECTED] wrote:
 As it stands, I always write the following in ES3

 var f = function() {};

 and now that arguments.callee is on the chopping block, I've started
 writing recursion as the painful contortion below

 var f = (function() {
  var callee = function() { callee(); };
  return callee;
 })();
 I don't get it. Why not write

   var f = function() { f(); };
 
 var f = function() {f();};
 var g = f;
 f = function(){alert('broke your recursion :)');};
 g();

/*const*/ var f = function() { f(); };

Then just treat /*const*/ variables as if they were 'const', until
at some point you no longer care about old versions of JScript and
can globally replace '/*const*/ var' - 'const'.

-- 
David-Sarah Hopwood
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Revenge of the double-curly [Was: return when desugaring to closures]

2008-10-11 Thread Brendan Eich
On Oct 11, 2008, at 7:25 AM, David-Sarah Hopwood wrote:

 It is correct to say, though, that:

  function foo() {
...
{ var bar = baz; }
...
  }

 is equivalent to

  function foo() {
let bar = undefined;
...
{ bar = baz; }
...
  }

 That is, 'var' need not be primitive. Only 'let' needs to be  
 primitive.

Indeed.


 Similarly, if we are careful in specifying 'lambda' then 'function'  
 need
 not be primitive, since it will be expressible as a rewrite to  
 'lambda'.

Yes, this is called out already in

http://wiki.ecmascript.org/doku.php?id=strawman:lambdas

/be


___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread Peter Michaux
On Sat, Oct 11, 2008 at 11:59 AM, Brendan Eich [EMAIL PROTECTED] wrote:
 On Oct 11, 2008, at 9:05 AM, Peter Michaux wrote:

 How to define a variable that is local to the enclosing lambda? Isn't
 the ability to do that essential?

 Use let (the var replacement declaration form).

Sounds good to me but it is a little confusing to keep track if let
is either in or out of ES-Harmony and if it is partly in then which of
the several JavaScript 1.7 uses are in and if there will be let,
let*, letrec semantics.

Peter
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread David Herman
 Also, I wonder why lambda in it's block-less form is restricted to
 expressions.

I'm with you... but I'd want to check with the experts on the ES grammar to see 
whether this introduces any nasty ambiguities.

Dave
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread David Herman
 Sounds good to me but it is a little confusing to keep track if let
 is either in or out of ES-Harmony and if it is partly in then which
 of
 the several JavaScript 1.7 uses are in and if there will be let,
 let*, letrec semantics.

I've got no crystal ball, but I'd say it'd be unlikely (and terribly silly) 
that we'd have `lambda' without having `let'.

(The `lambda' form would fail in its requirement as an equivalence-preserving 
primitive if it became a target of `var'-hoisting.)

Dave
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread Mark S. Miller
On Sat, Oct 11, 2008 at 12:52 PM, Peter Michaux [EMAIL PROTECTED] wrote:
 Use let (the var replacement declaration form).

 Sounds good to me but it is a little confusing to keep track if let
 is either in or out of ES-Harmony and if it is partly in then which of
 the several JavaScript 1.7 uses are in and if there will be let,
 let*, letrec semantics.

The let declaration is in. Like const and function declarations, it
has block-level letrec lexical scoping. I continue to oppose let
expressions and let statements, as they don't provide enough
additional power to justify their cost. For example, if lambda
supports optional args, as I think we all agree it should, then,
adapting a suggestion of Lars, we should define the scope in which the
default value expressions are evaluated so that

var x = 2;

(lambda (x = 3, y = x) (x+y))()

returns 5, not 6. This gives us an easy enough let. The builtin let
declarations provide an easy letrec. Given these, no one will miss
let*.

-- 
Cheers,
--MarkM
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread Peter Michaux
On Sat, Oct 11, 2008 at 1:21 PM, Mark S. Miller [EMAIL PROTECTED] wrote:

 The let declaration is in. Like const and function declarations, it
 has block-level letrec lexical scoping. I continue to oppose let
 expressions and let statements, as they don't provide enough
 additional power to justify their cost. For example, if lambda
 supports optional args, as I think we all agree it should, then,
 adapting a suggestion of Lars, we should define the scope in which the
 default value expressions are evaluated so that

var x = 2;

(lambda (x = 3, y = x) (x+y))()

Simplifying

(lambda (x = 3, y = x) (x+y))()

to just

let (x = 3, y = x) (x+y)

makes it much more clear when reading code what the intention of the
programmer was. The reader doesn't need to interpret the code with as
many steps and doesn't need to check at the end of the expression to
see if the lambda is immediately called or not. This checking is an
issue when an immediately called lambda spans more than a screen.
Repeatedly writing the whole immediately-called, anonymous function is
boilerplate for such a common pattern. I admit it is not much
character boiler plate but it is the fact that the pattern is so
common that I believe the concept is worth abstracting. It is the
mental boilerplate that is the waste.

Peter
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread Brendan Eich
On Oct 11, 2008, at 12:55 PM, David Herman wrote:

 How to define a variable that is local to the enclosing lambda? Isn't
 the ability to do that essential?

 No. With all due respect to Brendan, `var' hoisting to the top of a  
 function body is one of the more problematic aspects of ES's  
 semantics.

I agree, it's no skin off my nose -- 'var' hoisting was an artifact of  
function implementation in Netscape 2, and did not apply to global  
vars then. It was standardized as hoisting in all kinds of code  
(global, function, and eval). We are stuck with it. However, hoisting  
still applies to let:


 If you want a local variable, use `let' -- it'll be local to its  
 containing block. If you want a variable that is local to the entire  
 body of a `lambda', use `let' at the top level of the `lambda' body.

While let is local to containing block, the let-as-new-var proposal  
(implemented in Firefox 2 and up) hoists to top of block. So you  
cannot initialize the inner x using the outer x's value:

   {
 let x = 42;
 {
   let x = x; // undefined, not 42.
   alert(x);
 }
 alert(x); // 42, of course
   }

We've discussed making use-before-set a strict error, but we've  
avoided it. The initialiser is not mandatory, and we do not wish to  
impose costly analysis on small implementations.

/be
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread Brendan Eich

On Oct 11, 2008, at 12:52 PM, Peter Michaux wrote:

On Sat, Oct 11, 2008 at 11:59 AM, Brendan Eich [EMAIL PROTECTED]  
wrote:

On Oct 11, 2008, at 9:05 AM, Peter Michaux wrote:

How to define a variable that is local to the enclosing lambda?  
Isn't

the ability to do that essential?


Use let (the var replacement declaration form).


Sounds good to me but it is a little confusing to keep track if let
is either in or out of ES-Harmony


I do not see why you are confused. I wrote, in the original  
ECMAScript Harmony post:


 I heard good agreement on low-hanging de-facto standard fruit,
 particularly let as the new var, to match block-scoped const as still
 proposed (IIRC) in 3.1.

See https://mail.mozilla.org/pipermail/es-discuss/2008-August/006837.html 
.




and if it is partly in then which of
the several JavaScript 1.7 uses are in and if there will be let,
let*, letrec semantics.


It's something else. See my reply about hoisting, just sent.

/be

___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread Brendan Eich
On Oct 11, 2008, at 2:43 PM, Brendan Eich wrote:

 On Oct 11, 2008, at 12:52 PM, Peter Michaux wrote:

 and if it is partly in then which of

 the several JavaScript 1.7 uses are in and if there will be let,
 let*, letrec semantics.

 It's something else. See my reply about hoisting, just sent.

Mark and others have described the let declaration (let as new var) as  
like letrec. Close, but since forward references are possible and  
initiialization in the declaration is not mandatory, it's analogous,  
not identical. The function definition form in JS is letrec. But let  
as new var? I still say it's something else; I admit that like  
letrec or letrec-ilke works.

/be
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread Mark S. Miller
Hi Dave, first, my compliments on your lambda proposal. This should
significantly simplify the core language after expanding sugars --
especially if you succeed at redefining function as desugaring to
lambdas. That would be awesome!


On Sat, Oct 11, 2008 at 5:34 AM, David Herman [EMAIL PROTECTED] wrote:
 Here's roughly the semantics of return-to-label:

 - return-to-label first checks to see if the label is live on the stack
 - if not, it raises an exception from the point where the return was attempted
 - but if so, it attempts to unwind the stack to the point where the label was 
 executed, passing through any intervening finally clauses
 - if any of the finally clauses has its own non-local exit, this interrupts 
 and aborts the unwinding

 Thank you for pointing out, though, that try/catch isn't so easily defined on 
 top of return-to-label, since it still needs special handling for finally. 
 The options are either to define a lower-level primitive underlying 
 try/finally (akin to Scheme's dynamic-wind), or to leave exceptions -- or at 
 least try/finally -- as primitive. I lean towards the latter; dynamic-wind is 
 a subtle beast.

 [For those interested in dynamic-wind, Flatt et al's ICFP 07 paper has a nice 
 investigation into its semantics: 
 http://www.cs.utah.edu/plt/publications/icfp07-fyff.pdf]

I haven't looked at the Flatt paper yet. But the semantics you explain
above corresponds exactly to E's escape expressions. And E also treats
try/finally primitive for similar reasons. (Historical note: The E
escape construct and the call/ec previously explained both originate
in an escape statement by Reynolds from a paper in the late 60s or
early 70s. I don't recall whether Reynolds had any mechanism analogous
to try/finally.)

-- 
Cheers,
--MarkM
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread Brendan Eich
On Oct 11, 2008, at 2:55 PM, Mark S. Miller wrote:

 On Sat, Oct 11, 2008 at 2:42 PM, Brendan Eich [EMAIL PROTECTED]  
 wrote:
 We've discussed making use-before-set a strict error, but we've
 avoided it. The initialiser is not mandatory, and we do not wish to
 impose costly analysis on small implementations.

 Since const use-before-set is an unconditional error (i.e., not
 dependent on strictness), implementations already have to pay for a
 read-barrier mechanism. Since we'd like to support
 type-annotation-constraints on initialized let variables, I think
 initialized let variables should have an unconditional read barrier as
 well.

If using an uninitialized let binding is an error, then hoisting is  
pointless except to make the statements between start of block and the  
let declaration a dead zone for the binding name. This fits the  
ancient, weak but not entirely worthless post-hoc rationale for var  
hoisting (to avoid confusion among novice or inexperienced programmers  
by making many scopes, each implicitly opened by var), but it's not  
particularly useful.

What's more, as discussed here and in TC39, repeated let declarations  
for the same binding name within the same block should be allowed.  
Anything else is user- and refactoring-hostile. So the non-initial let  
declarations for a given name in the same block would be ignored.

This leaves efficiency as a concern. If implementations do not do the  
analysis required to catch use before set at compile time, then let as  
well as const pays the read barrier price. It's non-trivial. Today let  
(and var in the absence of eval) can be optimized to use a read in  
the VM, possibly even a load instruction -- no getter barrier  
required. Whatever the GC write barrier cost, reads dominate and this  
is a significant savings.

On the other hand, computing SSA including dominance relations while  
parsing (in one pass) is possible so long as we do not add goto to the  
language. So maybe the analysis is acceptable to modern  
implementations, which are increasingly sophisticated.

Still, it is not yet agreed that let use before set shall be an error.  
It certainly is not the case for var, and working code counts on the  
undefined default initial value.

/be
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread Mark S. Miller
On Sat, Oct 11, 2008 at 3:26 PM, Brendan Eich [EMAIL PROTECTED] wrote:
 Of course, let expressions would need lambda-coding no matter what
 names were shadowed. The experience gained in JS1.7+ shows more let
 block usage than let expression, but expression temporaries (lacking
 macros and ignoring automatically generated code) are uncommon in
 today's JS. The function-expression-immediately-applied cliché usually
 has statements for effect, if not a return -- not a single expression
 in its body.


Here's an odd idea. (I'm not yet advocating this; just brainstorming)

What if the body of a lambda were always a block (curlies enclosing a
statement list), but, by analogy to eval, if the last statement
executed is an expression statement, then invoking the lambda returns
the value of that last expression statement. Let's say, further, that
a lambda's parameter list is syntactically optional. Together, this
would result in

lambda{  }

being a first-class control-flow block as in Smalltalk. Then, if we
did want let-blocks that desugar to lambda, with no additional
complexity, a let block could be an expression even though its body
had statements. One construct would serve both as let expressions and
let blocks, and would for free turn JavaScript into an expression
language.

3 + let{ while(...){...}; 4; }

would either not terminate or evaluate to 7. None of this would violate TC.

-- 
Cheers,
--MarkM
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: return when desugaring to closures

2008-10-11 Thread Mark S. Miller
On Sat, Oct 11, 2008 at 4:05 PM, Dave Herman [EMAIL PROTECTED] wrote:
 Read the proposal again: the statement form of lambdas *does* return the
 value of its last expression; this is what ES3 calls the completion value.

Cool! So why are we still discussing proposed let expressions and let
blocks as distinct constructs?

-- 
Cheers,
--MarkM
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss