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
Yuh-Ruey Chen wrote:
> 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
> [email protected]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
Es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss