Re: Proposal: opt-out local scoping

2008-09-05 Thread Yuh-Ruey Chen
Yes, Dave Herman already mentioned that, and I replied with this:

While this is true, this is far less of a problem than opt-in local
scoping, because the errors with opt-out local scoping are always going
to be local to the block/function the variable was assigned in.

Because of this, I believe the convenience is worth the cost.


Waldemar Horwat wrote:
 With this proposal you just get the dual problem:  You think you're assigning 
 to an outer-scope variable while in fact you're creating and later discarding 
 a local variable.  This would just flip the confusion you worry about to the 
 other case without eliminating it.

 ES proposals already provide a good solution to this problem:  strict mode.  
 In strict mode you can't accidentally create a global just because you have a 
 missing var.  You get an error if you try.

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


Code blocks (was Re: Proposal: opt-out local scoping)

2008-08-30 Thread Yuh-Ruey Chen
Mark S. Miller wrote:
 Since ES is not an expression language, it's useful to divide the question 
 into

 * TC for expressions
expr equiv (function(){return expr;})()
ES violations: this, arguments.
'this' breakage can possibly be addressed with '.bind(this)' as in
 my previous message.
expr equiv (function(){return expr;}).call(this)

 * TC for blocks
{stats} equiv (function(){stats})();
Same issues re this, arguments
Additional ES violations: return, break, continue, var hoisting

 Note: The above litany of problems are not fixable in ES. But we
 should try to avoid digging this hole any deeper.

Any procedural language will have issues with TC then. The only longterm
solution to this that I can think of is to add Ruby-like code blocks to
the language, which inherit this, arguments, var scope, and
return/break/continue continuations.

Not ever having dealt with implementing continuations, I have no idea
how simple it would be to add code block semantics to the language.

There are two styles to code blocks that I know of, which are not
mutually exclusive:
1) adding a new type of function
2) denoting that a parameter to a function is a block, and treating any
function passed in as that parameter to be a block

In either style, the function artifacts (this, arguments, etc.) would be
determined lexically.

The first style would require some new syntax to define blocks.
Redefining |this| via function.call and function.apply should also be
disallowed. We have several options to choose from. Some examples:

Ruby-like:
do(...) { ... }
do { ... }

Usage of Java keywords:
function(...) inherits { ... }

Some obscure yet convenient syntax:
#(...) { ... }

The second style would require some sort of block annotation to a
parameter, e.g.

function(x: block} { ... }
function(block x) { ... }
function(x) { ... }

One advantage of the second style is that we can add new types of
control abstractions relatively seamlessly with some more Ruby-like
sugar. If the last parameter to a function is annotated to be a block,
then the following:

function control(..., block f) { ... }

control(...) statement

would pass in a 0-parameter code block composed of |statement| (which
could be a {...} block) to the function |control| as the parameter f.
Example:

function read(openArg, block f) {
try {
   this.open(openArg);
   f();
} finally {
   this.close();
}
}
   
FileInputStream.prototype.read = read;
   
function findInFiles(files, x) {
for each (let file in files) {
input = new FileInputStream();
input.read(file) {
let lineNum = 0;
for (let line in input.readLines()) {
if (line == x)
return [file, lineNum];
lineNum++;
}
}
}
}

Hope that all made sense.

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


Proposal: opt-out local scoping

2008-08-28 Thread Yuh-Ruey Chen
Well we're all discussing radical new syntaxes (I'm looking at you,
Ingvar), I might as well propose my own.

One thing about JavaScript that has always really bothered me (and
probably several of you) is how JavaScript has opt-in local scope,
rather than opt-out local scope. That is, in order to have an identifier
reference a local variable, there needs to be a |var| declaration that
says that that identifier refers to a local variable, and not non-local
one (either in a surrounding function or the global scope). This has a
couple related problems:

1) Lack of integrity - in that it's easy to shoot yourself in the foot.
One missing |var| and you can be debugging some random error in the
wrong place.

2) It's inconvenient. This is pretty self-explanatory. It also
encourages the usage of redundant var declarations in
often-copied/pasted code, even if it may not be necessary due to var
hoisting, which is apparently a practice some people here are not fond of.

3) It can be confusing due to var hoisting. Suppose you have code like this:

blah = 10;
(function() {
print(blah);
var blah = 20;
print(blah);
})();

The novice user would expect this to print 10 followed by 20, when
it really prints out undefined followed by 20.

This has all been discussed to death before, I'm sure, with the
conclusion that changing the behavior is backwards incompatible. And I
vaguely remember someone saying that we shouldn't add a pragma to fix
this issue, although the reason for that escapes me at the moment.


So here's the proposal that is backwards compatible: provide a block
that changes the default scoping.

var { ... }

where everything assigned in ... results in a variable local to that
block. Note that this only affects _assignment_. You can still read from
a variable from a surrounding scope.

As some extra sugar,

function name(args) var { ... }

would desugar

function name(args) { var { ... } }

The default scoping setting also nests, i.e. it also crosses function
boundaries, so in

var {
function name(args) { ... }
}

everything assigned in ... results in a variable local to the functions
block.

To escape (opt out) of the scoping setting, we need a new keyword.
Python 2.5 uses the keyword |nonlocal| for this purpose, so I'll use it
as well as a placeholder.

var {
...
nonlocal x [ = y];
...
}

Finally, we can do the same thing for |let|:

let { ... }

etc.

Some examples:

---

function list(iterable) {
var {
if (iterable is Array) {
lst = iterable;
} else {
list = [];
for (x in iterable) {
lst.push(x);
}
}
}
return lst;
}

function stats(iterable) var { // -- notice var
lst = list(iterable);
   
function calcSum() {
sum = 0;
for each (x in lst) {
sum += x;
}
}
   
sum = calcSum();
   
var mean;
   
function calcMean() {
   nonlocal mean;
   mean = sum / lst.length;
}
   
return [lst.length, sum, mean];
}

---

which desugars to:

---

function list(iterable) {
var lst;
if (iterable is Array) {
lst = iterable;
} else {
list = [];
for (var x in iterable) {
lst.push(x);
}
}
return lst;
}

function stats(iterable) {
var lst = list(iterable);
   
function calcSum() {
var sum = 0;
for each (var x in lst) {
sum += x;
}
}
   
var sum = calcSum();
var mean = sum / lst.length;
return [lst.length, sum, mean];
}

---

And finally, it would be nice to have a pragma that can do this for us
(again, I don't recall the argument against them). Something like:

use scope var;
use scope let;
use scope nonlocal; // default for backwards compatibility

which would obviate the need to add all these |var { ... }| and |let {
... }| statements in new code.

For example, the following would be equivalent to the above examples:

---

use scope var;

function list(iterable) {
if (iterable is Array) {
lst = iterable;
} else {
list = [];
for (x in iterable) {
lst.push(x);
}
}
return lst;
}

function stats(iterable) {
lst = list(iterable);
   
function calcSum() {
sum = 0;
for each (x in lst) {
sum += x;
}
}
   
sum = calcSum();
   
var mean;
   
function calcMean() {
   use scope nonlocal;   // notice that these pragmas can be local
to blocks
   mean = sum / lst.length;
}
   
return [lst.length, sum, mean];
}

---

I should also point out that this is not a radical new concept. Both
Ruby and Python have had this functionality for a while. Comments?

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


Re: Proposal: opt-out local scoping

2008-08-28 Thread Dave Herman
I agree with you 100% that JavaScript /almost/ gets lexical scope right 
and that we should try to eliminate that almost as much as we can. I 
don't, however, believe that the right solution is Python's implicit 
binding semantics.

 where everything assigned in ... results in a variable local to that
 block. Note that this only affects _assignment_. You can still read from
 a variable from a surrounding scope.

I think you're still going to have the same subtleties as hoisting with 
this proposal, since all the variables assigned to in the block will be 
in scope for the whole block; so they'll be `undefined' before being 
assigned to and there will still be the same closure hazards where you 
might think the variable was in scope in a nested block but in fact it 
goes out to the nearest enclosing var { ... } block.

 var {
 ...
 nonlocal x [ = y];
 ...
 }

For my tastes, this puts too much of a tax on referring to outer variables.

 function list(iterable) {
 var {
 if (iterable is Array) {
 lst = iterable;
 } else {
 list = [];

I think you mean `lst = []' here?

 for (x in iterable) {
 lst.push(x);
 }
 }
 }
 return lst;
 }

These are the kinds of bugs that I think this semantics would result in: 
when assignment implicitly binds variables, fat-fingering an assigned 
variable name silently works and then causes unpredictable behavior 
later. Whereas with traditional lexical scope, when you declare your 
variables up front, both assignments and references are checked against 
the variables in scope, and you get an immediate error -- even 
statically detectable.

I don't believe that

 var {
 ...
 a = f()
 ...
 b = g()
 ...
 c = h()
 ...
 }

is that much less of a hardship than

 {
 ...
 var a = f()
 ...
 var b = g()
 ...
 var c = h()
 ...
 }

and I believe the benefits of a clearer semantics -- and clearer and 
earlier errors on assignment to free variables -- are worth it. But I 
agree that we need to do something to correct the semantics of looking 
up free variables dynamically.

 And finally, it would be nice to have a pragma that can do this for us
 (again, I don't recall the argument against them). Something like:
 
 use scope var;
 use scope let;
 use scope nonlocal; // default for backwards compatibility

Lexical scope is in the air.  :)  Please take a look at the lexical 
scope proposal on the wiki and offer any comments or suggestions:

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

Essentially, the above is a less radical proposal that simply uses the 
lexical scope that's already there in JavaScript, but as you suggest 
enforces it with a pragma. The result is a language where free 
variables, both in assignments and references, are a statically 
detectable error, but with otherwise essentially the same semantics that 
JavaScript already has.

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


Re: Proposal: opt-out local scoping

2008-08-28 Thread P T Withington
On 2008-08-28, at 07:52EDT, Dave Herman wrote:

 Lexical scope is in the air.  :)  Please take a look at the lexical
 scope proposal on the wiki and offer any comments or suggestions:

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

 Essentially, the above is a less radical proposal that simply uses the
 lexical scope that's already there in JavaScript, but as you suggest
 enforces it with a pragma. The result is a language where free
 variables, both in assignments and references, are a statically
 detectable error, but with otherwise essentially the same semantics  
 that
 JavaScript already has.

I like this, but wouldn't you want to provide escapes, like reformed  
with and/or a way to declare an individual reference to be free?
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proposal: opt-out local scoping

2008-08-28 Thread Dave Herman
 I like this, but wouldn't you want to provide escapes, like reformed 
 with and/or a way to declare an individual reference to be free?

Reformed `with' depended on type annotations and structural type syntax, 
which are undergoing discussion. So I think reformed `with' is up in the 
air for now.

As for free references, what can you do with a free variable? If you 
mean you want a way to look something up in the global object, then use 
`this.id' or `this[expr]' (or `let global = this' followed by 
global.id/global[expr]).

It might be nice to have a standard library (called `global' or 
something) that's bound to the global object so you can have a less 
fragile binding to the global object than `this'.

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


Re: Proposal: opt-out local scoping

2008-08-28 Thread P T Withington
On 2008-08-28, at 09:09EDT, Dave Herman wrote:

 As for free references, what can you do with a free variable? If you  
 mean you want a way to look something up in the global object, then  
 use `this.id' or `this[expr]' (or `let global = this' followed by  
 global.id/global[expr]).

 It might be nice to have a standard library (called `global' or  
 something) that's bound to the global object so you can have a less  
 fragile binding to the global object than `this'.

Exactly.  I think it would be worthwhile to have a standard way to  
refer to the global object.
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proposal: opt-out local scoping

2008-08-28 Thread Yuh-Ruey Chen
Dave Herman wrote:
 I think you're still going to have the same subtleties as hoisting with 
 this proposal, since all the variables assigned to in the block will be 
 in scope for the whole block; so they'll be `undefined' before being 
 assigned to and there will still be the same closure hazards where you 
 might think the variable was in scope in a nested block but in fact it 
 goes out to the nearest enclosing var { ... } block.

Actually, I forgot to mention that in there should no longer be any
hoisting in this case; it should be a syntax error:

blah = 10;
var {
print(blah);
blah = 20;
print(blah);
}

The first |print(blah)| should be a syntax error. I think this is what
Python does too.

  var {
  ...
  nonlocal x [ = y];
  ...
  }

 For my tastes, this puts too much of a tax on referring to outer variables.

The alternative, which Pythonites have used for a while until the advent
of |nonlocal|, was to have an object/array in the outer scope and have
the outer variable be a property of that object:

var {
function outer() {
x = 10;
a = [x];
function inner() {
   return a[0];
}
return inner();
}
}

However, this is pretty ugly and isn't very discoverable.

 These are the kinds of bugs that I think this semantics would result in: 
 when assignment implicitly binds variables, fat-fingering an assigned 
 variable name silently works and then causes unpredictable behavior 
 later. Whereas with traditional lexical scope, when you declare your 
 variables up front, both assignments and references are checked against 
 the variables in scope, and you get an immediate error -- even 
 statically detectable.

While this is true, this is far less of a problem than opt-in local
scoping, because the errors with opt-out local scoping are always going
to be local to the block/function the variable was assigned in.

Because of this, I believe the convenience is worth the cost.

 I don't believe that

  var {
  ...
  a = f()
  ...
  b = g()
  ...
  c = h()
  ...
  }

 is that much less of a hardship than

  {
  ...
  var a = f()
  ...
  var b = g()
  ...
  var c = h()
  ...
  }

 and I believe the benefits of a clearer semantics -- and clearer and 
 earlier errors on assignment to free variables -- are worth it. But I 
 agree that we need to do something to correct the semantics of looking 
 up free variables dynamically.

I don't particularly like |var { ... }| myself, but it's the only other
way besides a pragma - I would much prefer a pragma, which would pretty
much eliminate the usage of |var|.

  And finally, it would be nice to have a pragma that can do this for us
  (again, I don't recall the argument against them). Something like:
  
  use scope var;
  use scope let;
  use scope nonlocal; // default for backwards compatibility

 Lexical scope is in the air.  :)  Please take a look at the lexical 
 scope proposal on the wiki and offer any comments or suggestions:

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

 Essentially, the above is a less radical proposal that simply uses the 
 lexical scope that's already there in JavaScript, but as you suggest 
 enforces it with a pragma. The result is a language where free 
 variables, both in assignments and references, are a statically 
 detectable error, but with otherwise essentially the same semantics that 
 JavaScript already has.

 Dave
   

I've taken a look at that, and while it does address free variables, I'd
still rather not have to sprinkle redundant |var|s everywhere.
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proposal: opt-out local scoping

2008-08-28 Thread Dave Herman
 For what value of global should the global keyword be global? };-

I'm not sure if this is what Erik meant, but my intention was just that 
there's a variable bound in the standard library called `global' that's 
bound to the global object. The only reason I suggested the name 
`global' was that the spec uses the terminology the global object. But 
there's nothing special about the variable; it can be shadowed like any 
other variable.

I interpreted Erik's point to be that the binding of `this' is not 
lexically scoped, so it would be useful to have a lexically scoped 
variable initially bound to the global object. IOW, if I write:

 this.print(blah blah blah)

and then I refactor the code to say:

 (function() {
 this.print(blah blah blah)
 })()

it breaks. By contrast if I have a standard library binding `global' 
that's bound to the same thing as `this' at the top level, then I can write:

 global.print(blah blah blah)

and the same refactoring:

 (function() {
  global.print(blah blah blah)
 })()

continues to work the same. But there's no need for a special keyword or 
anything like that.

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


Re: Proposal: opt-out local scoping

2008-08-28 Thread ihab . awad
On Thu, Aug 28, 2008 at 12:14 PM, Dave Herman [EMAIL PROTECTED] wrote:
 For what value of global should the global keyword be global? };-

 I interpreted Erik's point to be that the binding of `this' is not lexically
 scoped, so it would be useful to have a lexically scoped variable initially
 bound to the global object. IOW, if I write:

global.print(blah blah blah)

 and the same refactoring:

(function() {
 global.print(blah blah blah)
})()

 continues to work the same.

Cool. Would there be a 'global' for each module (for some
interpretation of module but assuming each module has its own
separate top-level lexical scope, as appears to be the growing
concensus)?

 But there's no need for a special keyword or anything like that.

Would that really satisfy Erik's use case? He seemed to think that
doing, at the top level --

  var global = this;

  function foo() {
global.bar = 3;
  }

is vulnerable to some ${person} going --

  function foo() {
var global = /* something else */
global.bar = 3; /* now not the *real* global; system fails! */
  }

?

Ihab

-- 
Ihab A.B. Awad, Palo Alto, CA
___
Es-discuss mailing list
Es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proposal: opt-out local scoping

2008-08-28 Thread Brendan Eich
On Aug 28, 2008, at 12:14 PM, Dave Herman wrote:

 I interpreted Erik's point to be that the binding of `this' is not
 lexically scoped, so it would be useful to have a lexically scoped
 variable initially bound to the global object. IOW, if I write:

  this.print(blah blah blah)

 and then I refactor the code to say:

  (function() {
  this.print(blah blah blah)
  })()

 it breaks.

It happens not to break, because ES3 requires a null |this| for such  
calls, where the null is later replaced by the global object.

obj = {
 method: function () { this.print(blah blah blah); },
 print:  function () { print(not the print you want); }
};
obj.method();

would break, though.

We've been trying to fix the ES3 null-global rule for a while. Any  
change is an incompatible change, but the current rule leads to  
unintended global mutation and capture bugs.


 By contrast if I have a standard library binding `global'
 that's bound to the same thing as `this' at the top level, then I  
 can write:

  global.print(blah blah blah)

 and the same refactoring:

  (function() {
   global.print(blah blah blah)
  })()

 continues to work the same. But there's no need for a special  
 keyword or
 anything like that.

Indeed, Doug Crockford proposed at the January TC39 meeting this year  
to make 'this' act like a lexically bound variable, with the only  
magic to it applying to the case of obj.method() call expressions  
(and variatons, obj[name] where name = 'method'), where 'this' would  
be overridden -- if you will, a shadowing 'this' would be bound to obj.

I liked Doug's proposal quite a bit. I do not see anything like it in  
ES3.1, but I'd like to see it in Harmony.

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


Re: Proposal: opt-out local scoping

2008-08-28 Thread Brendan Eich
On Aug 28, 2008, at 1:23 PM, P T Withington wrote:

 I'd like to have a syntax where this is _not_ implicitly bound.  One
 idea would be to riff on default arguments:

function example (receiver=this, ...

Why wouldn't you use |this| for the parameter name? We did for type- 
annotating |this| in various proposals.

Some functions have a bound |this| when you extract them. Such  
override attempts would fail. Throw or fail silently?

/be

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


Re: Proposal: opt-out local scoping

2008-08-28 Thread Erik Arvidsson
On Thu, Aug 28, 2008 at 12:29, Dave Herman [EMAIL PROTECTED] wrote:

 Would that really satisfy Erik's use case? He seemed to think that
 doing, at the top level --

  var global = this;

  function foo() {
global.bar = 3;
  }

 is vulnerable to some ${person} going --

  function foo() {
var global = /* something else */
global.bar = 3; /* now not the *real* global; system fails! */
  }

 You can make the same case for any variable. This is just lexical scope in
 action. The meaning of a variable reference is its innermost lexical
 binding. If you shadow a variable, it's shadowed.

 Erik, was this your concern?

I'm not concerned about someone shadowing it.  My concern was with
cases like the one Brendan pointed out as well as code snippets like:

new function() {
  var global = this;
  global.print(124);
}

Some people tend to use that format over (function() { })() and
wrapping code with that construct would break the global reference.

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


Re: Proposal: opt-out local scoping

2008-08-28 Thread Ingvar von Schoultz
Dave Herman wrote:
 Reformed `with' depended on type annotations and structural type syntax, 
 which are undergoing discussion. So I think reformed `with' is up in the 
 air for now.

I find it odd that reformed |with| required such exact type
annotations, when nothing else does. It would seem that these
are very similar, from an early-binding viewpoint:

 var {a, b, c} = fn();
 x = a;

 var obj = fn();
 x = obj.a;
 with (obj : {a, b, c})
 {   x = a; // Desugars to obj.a
 }

Equally it would seem that disambiguating syntax would allow
early binding, if it were enforced:

 with (obj)
 {   x = .a; // Desugars to obj.a
 y = a;  // From the lexical scope
 }

-- 
Ingvar von Schoultz

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


Re: Proposal: opt-out local scoping

2008-08-28 Thread Brendan Eich
On Aug 28, 2008, at 2:59 PM, Ingvar von Schoultz wrote:

 Dave Herman wrote:
 Reformed `with' depended on type annotations and structural type  
 syntax,
 which are undergoing discussion. So I think reformed `with' is up  
 in the
 air for now.

 I find it odd that reformed |with| required such exact type
 annotations, when nothing else does.

Please read

http://wiki.ecmascript.org/doku.php?id=proposals:reformed_with

the last paragraph in particular.


 It would seem that these
 are very similar, from an early-binding viewpoint:

  var {a, b, c} = fn();
  x = a;

  var obj = fn();
  x = obj.a;
  with (obj : {a, b, c})
  {   x = a; // Desugars to obj.a
  }

Your example includes neither type constraints nor mutation.


 Equally it would seem that disambiguating syntax would allow
 early binding, if it were enforced:

  with (obj)
  {   x = .a; // Desugars to obj.a

New syntax could solve the ambiguity problem, but not the type  
variance problem.

/be

  y = a;  // From the lexical scope
  }

 -- 
 Ingvar von Schoultz

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

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