local

# Ingvar von Schoultz (17 years ago)

The keyword "let" breaks the very valuable JavaScript tradition of using intuitively meaningful keywords.

JavaScript uses the word to say "local", but its normal English meaning is "allow".

All other JavaScript keywords help you understand the program text. Most of them suggest a translation from statement to plain English that conveys the meaning reasonably well. The totally off-the-mark meaning of "let" makes it strange and foreign.

You'd get nicely intuitive plain English if "local" were used instead:

 if (x == 5)
 {   local y = 3;
     z = x * y;
 }
 for (local Key in List)
     ++List [Key];

Of course one can easily guess intuitively at the historical accidents that have led people to use "let" when they really mean to say "local". But that's no reason for burdening JavaScript with such an off-the-mark word, in my opinion.

# Peter Michaux (17 years ago)

On Wed, Aug 20, 2008 at 8:21 AM, Ingvar von Schoultz <ingvar-v-s at comhem.se> wrote:

The keyword "let" breaks the very valuable JavaScript tradition of using intuitively meaningful keywords.

I have read a lot of math proofs that start with "let x be the..."

I like "let" as the new keyword.

[snip]

Peter

# Ingvar von Schoultz (17 years ago)

Peter Michaux wrote:

On Wed, Aug 20, 2008 at 8:21 AM, Ingvar von Schoultz <ingvar-v-s at comhem.se> wrote:

The keyword "let" breaks the very valuable JavaScript tradition of using intuitively meaningful keywords.

I have read a lot of math proofs that start with "let x be the..."

That's exactly the problem. The word makes perfect sense, it has an easily understandable meaning. And this meaning has nothing at all to do with the localness that the word is used for.

The word suggests quite strongly that it's talking about the assignment. This is completely wrong, since it actually specifies the visibility scope of the name.

# Peter Michaux (17 years ago)

On Wed, Aug 20, 2008 at 8:47 AM, Ingvar von Schoultz <ingvar-v-s at comhem.se> wrote:

Peter Michaux wrote:

On Wed, Aug 20, 2008 at 8:21 AM, Ingvar von Schoultz <ingvar-v-s at comhem.se> wrote:

The keyword "let" breaks the very valuable JavaScript tradition of using intuitively meaningful keywords.

I have read a lot of math proofs that start with "let x be the..."

That's exactly the problem. The word makes perfect sense, it has an easily understandable meaning. And this meaning has nothing at all to do with the localness that the word is used for.

The word suggests quite strongly that it's talking about the assignment. This is completely wrong, since it actually specifies the visibility scope of the name.

I think "let" is fine as there is a long precedence for it in Lisp and at least in Mozilla's JavaScript implementation. It is short too.

JavaScript has some weird keyword uses. "var" means variable but actually specifies scope also to the surrounding function. "function" implies an actual function but JavaScript can have side effects anywhere. "undefined" doesn't really mean something is undefined as it could be defined to be undefined. Past wrongs don't justify future wrongs. I just don't think "let" is a wrong (I actually like it.)

Peter

# Jon Zeppieri (17 years ago)

On Wed, Aug 20, 2008 at 11:47 AM, Ingvar von Schoultz <ingvar-v-s at comhem.se> wrote:

Peter Michaux wrote:

On Wed, Aug 20, 2008 at 8:21 AM, Ingvar von Schoultz <ingvar-v-s at comhem.se> wrote:

The keyword "let" breaks the very valuable JavaScript tradition of using intuitively meaningful keywords.

I have read a lot of math proofs that start with "let x be the..."

That's exactly the problem. The word makes perfect sense, it has an easily understandable meaning. And this meaning has nothing at all to do with the localness that the word is used for.

The word suggests quite strongly that it's talking about the assignment. This is completely wrong, since it actually specifies the visibility scope of the name.

... except that let is used this way in other programming languages. The appeal is not (and ought not be) to the use of 'let' in English, especially since many ES programmers are not English speakers. The appeal is to the use of 'let' in other programming languages. Scheme and the ML family are the most relevant here.

# Allen Wirfs-Brock (17 years ago)

I think Ingvar bring up an interesting point. While this usage on "let" feels very natural to those of us who have had exposure to functional languages that use it in this manner, it may not be nearly so intuitive to the millions of "script writers" who will be exposed to it. (And, arguably, there are probably still quite a few more former BASIC programmers out there, to whom "let" means assignment, then there are Scheme and ML programmers.) In addition, while I can't personally speak to it, I can also see where there may be understandability issues for non-native English speakers.

I think it is a fine idea to consider usability issues like this as we work towards defining ES-Harmony.

# Sam Ruby (17 years ago)

On Wed, Aug 20, 2008 at 12:04 PM, Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com> wrote:

I think Ingvar bring up an interesting point. While this usage on "let" feels very natural to those of us who have had exposure to functional languages that use it in this manner, it may not be nearly so intuitive to the millions of "script writers" who will be exposed to it. (And, arguably, there are probably still quite a few more former BASIC programmers out there, to whom "let" means assignment, then there are Scheme and ML programmers.) In addition, while I can't personally speak to it, I can also see where there may be understandability issues for non-native English speakers.

I think it is a fine idea to consider usability issues like this as we work towards defining ES-Harmony.

Perl uses "my". Short. Implies scope.

perldoc.perl.org/functions/my.html

Allen

  • Sam Ruby
# Jon Zeppieri (17 years ago)

On Wed, Aug 20, 2008 at 12:12 PM, Sam Ruby <rubys at intertwingly.net> wrote:

On Wed, Aug 20, 2008 at 12:04 PM, Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com> wrote:

I think Ingvar bring up an interesting point. While this usage on "let" feels very natural to those of us who have had exposure to functional languages that use it in this manner, it may not be nearly so intuitive to the millions of "script writers" who will be exposed to it. (And, arguably, there are probably still quite a few more former BASIC programmers out there, to whom "let" means assignment, then there are Scheme and ML programmers.) In addition, while I can't personally speak to it, I can also see where there may be understandability issues for non-native English speakers.

I think it is a fine idea to consider usability issues like this as we work towards defining ES-Harmony.

Perl uses "my". Short. Implies scope.

perldoc.perl.org/functions/my.html

Allen

  • Sam Ruby

If we really are going by the plain English meaning, I'd say 'my' implies possession, not scope, and is more appropriate to describe the relation between an instance variable and its object than that of a lexical variable and its scope.

'local' would be fine, except that ES already has a kind of local variable. 'var'-declared variables are function-local. If you search for "javascript local variable," you will get plenty of results, and all of them will be about 'var.'

Allen's BASIC point is a good one, and all I can muster in response is a (mostly) tongue-in-cheek reply: BASIC programmers who go on to learn other languages first find it necessary to unlearn BASIC.

# Mark S. Miller (17 years ago)

On Wed, Aug 20, 2008 at 8:54 AM, Peter Michaux <petermichaux at gmail.com> wrote:

[...] "var" means variable but actually specifies scope also to the surrounding function. "function" implies an actual function but JavaScript can have side effects anywhere. "undefined" doesn't really mean something is undefined as it could be defined to be undefined. [...]

And there's that classic naming perversity:

typeof NaN === 'number'
# T. Michael Keesey (17 years ago)

On Wed, Aug 20, 2008 at 8:47 AM, Ingvar von Schoultz <ingvar-v-s at comhem.se> wrote:

Peter Michaux wrote:

On Wed, Aug 20, 2008 at 8:21 AM, Ingvar von Schoultz <ingvar-v-s at comhem.se> wrote:

The keyword "let" breaks the very valuable JavaScript tradition of using intuitively meaningful keywords.

I have read a lot of math proofs that start with "let x be the..."

That's exactly the problem. The word makes perfect sense, it has an easily understandable meaning. And this meaning has nothing at all to do with the localness that the word is used for.

Arguably it does. In mathematical writing, it implies that the following assignment is "local" to the current discussion or proof. That is, it's not a definition that has any relevance within other sections of the text.

(However, MathML uses "declare" for this purpose.)

# Michael Haufe (17 years ago)

Is it worth changing the name of a statement/expression/definition who's labeled intuitiveness is debatable and which has been in use since JavaScript 1.7? If compatibility is one of the goals wouldn't this create more trouble than its worth?

# Steven Johnson (17 years ago)

If intuitively-plain English is a requirement, we'll have to change some existing keywords... e.g., I submit that the meaning of "for" has little to do with typical English usage.

# Mark S. Miller (17 years ago)

On Wed, Aug 20, 2008 at 4:22 PM, Michael Haufe <TNO at thenewobjective.com> wrote:

Is it worth changing the name of a statement/expression/definition who's labeled intuitiveness is debatable and which has been in use since JavaScript 1.7? If compatibility is one of the goals wouldn't this create more trouble than its worth?

I think this is an adequate reason to stick with "let". Also, if we're arguing from the English meaning of "local", its two most obvious antonyms are "global" and "remote". Both non-global and non-remote are potentially meaningful concepts, but neither corresponds to the suggesting meaning of "local".

# Richard Cornford (17 years ago)

Michael Haufe wrote:

Is it worth changing the name of a statement/expression/definition who's labeled intuitiveness is debatable and which has been in use since JavaScript 1.7? If compatibility is one of the goals wouldn't this create more trouble than its worth?

Compatibility with JavaScript 1.7 is not nearly as important as compatibility with ES 3. It is not really a "will it break the web" question because while those features are syntax errors in IE they will not tend to be used on the web.

Still, there would be no reason for a JavaScript(tm) implementation of a future ES not providing both "local" and "let" with "let" being a syntax extension (as it is now in ES 3 terms), and giving them both identical meaning (and "let" can be deprecated so it may be removed at some future date). Thus providing compatibility with exiting JavaScript 1.7 specific code.

One question would be; if "local" is used to declare variables (with some specific scope) doesn't it then become a reserved word? And then, if an ES 3 script has used "local" as an Identifier doesn't it then find that Identifier causing a syntax error in a some future ES implementation? The alternative is interpreting "local" based on its context in the source code, but that has got to be harder than only seeing it as having one meaning.

While "let" is the type of word that does not lend itself to being used as a variable name, "local" may have been used to name something that embodied that concept.

I am quite happy with "let", but that is mostly because it is good enough for its job and short, where short is very appealing given the number of times I can expect to be typing it in the future.

Richard Cornford.

# Igor Bukanov (17 years ago)

2008/8/20 Ingvar von Schoultz <ingvar-v-s at comhem.se>:

The keyword "let" breaks the very valuable JavaScript tradition of using intuitively meaningful keywords.

JavaScript uses the word to say "local", but its normal English meaning is "allow".

A let declaration does not imply locality since let at the top level introduces precisely a global variable. Using local for that would be very confusing.

, Igor

# Ingvar von Schoultz (17 years ago)

Igor Bukanov wrote:

A let declaration does not imply locality since let at the top level introduces precisely a global variable. Using local for that would be very confusing.

I think of |local x| as an abbreviation of |local var x|, so in the global scope I'd omit |local| and write |var x|.

# Ingvar von Schoultz (17 years ago)

Steven Johnson wrote:

If intuitively-plain English is a requirement, we'll have to change some existing keywords... e.g., I submit that the meaning of "for" has little to do with typical English usage.

You can read "for..." as and abbreviation of "for each value i between 0 and 5, do this."

Keywords don't have to be exact and complete. Given that the "for" loop is useful and necessary, expressing it with "for" is arguably the closest we can get.

Our starting point must be the constructs that are useful and efficient in programming. Given these constructs, we try to find suitable words. This means that keywords will necessarily be inexact and incomplete.

The problem with "let" isn't inexactness or incompleteness, it's that it's completely off the mark and unrelated, when read as plain English. All other keywords are closely related to their in-program semantics in some way.

Regarding "for", a worse problem is this:

 for (var key in map) {...}

 for each (var value in map) {...}

Both constructs expand into the same plain-English sentence. I think this would be better:

 for (var key in map) {...}

 for (var value in values map) {...}

 for (var [key, value] in [keys, values] map) {...}
# Michael Haufe (17 years ago)

"The problem with "let" isn't inexactness or incompleteness, it's that it's completely off the mark and unrelated, when read as plain English. All other keywords are closely related to their in-program semantics in some way. "

As was stated earlier this is debatable. A quick search of the internet will show many contexts in which this word is used to denote exactly or similarly what it means here.

The Dictionary definition: "To grant the occupancy or use of ..."

Math statements: "Let x = the number of apples in the basket"

Similar use in other programming languages...

Perhaps Brendan or someone else can shed light on the original decision making process of "let"'s inclusion in JavaScript 1.7?

# Brendan Eich (17 years ago)

On Aug 21, 2008, at 6:12 AM, Michael Haufe wrote:

Perhaps Brendan or someone else can shed light on the original
decision making process of "let"'s inclusion in JavaScript 1.7?

We added let to JS1.7 based on the ES4 proposal:

proposals:block_expressions

The precedent for let is strong in many other languages, including
Scheme and the ML family.

Keyword connotations aside, let has clear denotation in many
programming languages. I don't think it's worthwhile for the list to
bike-shed too much when many on the TC39 committee have recently
expressed support for let declarations. More helpful would be
comments on the utility of let blocks (a.k.a. let statements) and let
expressions. Also comparisons to the several let forms in Scheme (Jon
Z. posted something a while ago on this topic).

# Peter Michaux (17 years ago)

On Thu, Aug 21, 2008 at 6:31 AM, Brendan Eich <brendan at mozilla.org> wrote:

More helpful would be comments on the utility of let blocks (a.k.a. let statements) and let expressions. Also comparisons to the several let forms in Scheme (Jon Z. posted something a while ago on this topic).

I was reading the resulting ticket a few days ago.

bugs.ecmascript.org/ticket/375

I think that the let statement

let (x = 2, y = x) { print(y); }

should desugar to exactly

(function(x, y) { print(y); })(2, x)

Also the let expression

z = let (x = 2, y = x) x + y;

should desugar to exactly

z = (function(x, y) x + y)(2, x);

The reasons for these particular desugarings is this is exactly what JavaScript programmers are writing today. It is common to see something like the desugared let statement above when looping and attaching event handlers to DOM elements, for example.

I also think that since the name is "let" that the above desugaring makes sense as the closest analogy to Scheme's let. It doesn't make sense to me to have JavaScript's let be Scheme's let* or letrec. All these lets are purely sugar coatings and I'm not opposed to having Scheme's let* and letrec added to JavaScript as they introduce even sweeter sugar for some situations. I suppose let* would need to be renamed.

Peter

# Jon Zeppieri (17 years ago)

On Thu, Aug 21, 2008 at 11:21 AM, Peter Michaux <petermichaux at gmail.com> wrote:

On Thu, Aug 21, 2008 at 6:31 AM, Brendan Eich <brendan at mozilla.org> wrote:

More helpful would be comments on the utility of let blocks (a.k.a. let statements) and let expressions. Also comparisons to the several let forms in Scheme (Jon Z. posted something a while ago on this topic).

I was reading the resulting ticket a few days ago.

bugs.ecmascript.org/ticket/375

I think that the let statement

let (x = 2, y = x) { print(y); }

should desugar to exactly

(function(x, y) { print(y); })(2, x)

Also the let expression

z = let (x = 2, y = x) x + y;

should desugar to exactly

z = (function(x, y) x + y)(2, x);

The reasons for these particular desugarings is this is exactly what JavaScript programmers are writing today. It is common to see something like the desugared let statement above when looping and attaching event handlers to DOM elements, for example.

I also think that since the name is "let" that the above desugaring makes sense as the closest analogy to Scheme's let. It doesn't make sense to me to have JavaScript's let be Scheme's let* or letrec. All these lets are purely sugar coatings and I'm not opposed to having Scheme's let* and letrec added to JavaScript as they introduce even sweeter sugar for some situations. I suppose let* would need to be renamed.

Peter

(That's now twice I sent this message from the wrong email address. Sorry about that. I'm replying only to the lists now.)

Just to be clear about this: my comments were directed at the claim that "let is the new var." It seemed that one of the design goals of the let declaration was that it should be a drop-in replacement for var, only with block scoping. That would require (in Scheme terms) letrec*-like semantics. Given

let x = 2, y = x * 2;

... the let-bound x would have to be visible to y's initializer. And given

let fn = function(n) { if (n === 0) return 1; else return n * fn(n - 1); };

... the 'fn' on the right hand side would refer to the let-bound value (and not to something in the enclosing scope).

That said, I happen to like plain let semantics. But if we use those semantics, then let is certainly not the new var.

Your comments above are about let statements and expressions. Since they have no 'var' analogue, the same considerations do not apply. However, it would be very odd to use letrec* semantics in one case and let semantics in the others.

So, here is a suggestion that, I am sure, no one but me will like: drop let declarations and only include let statements and expressions. Give them let semantics. Maybe this is only true of me, but if let statements were in the language, I would never use let declarations, anyway. The advantage of the statement and expression forms is that they make the scope of the let-bound variables explicit.

# Brendan Eich (17 years ago)

On Aug 21, 2008, at 8:21 AM, Peter Michaux wrote:

I think that the let statement

let (x = 2, y = x) { print(y); }

should desugar to exactly

(function(x, y) { print(y); })(2, x)

We've been over this. What if you replace print(y) with return y?

I had slides in 2006 talks on ES4 that showed how folks use closures
for everything, including scoped statements and scoped expressions.
That does not mean everything should desugar to function applications.

Besides the return issue, there are break and continue to consider,
and the arguments object.

Desugaring may seem all the rage from the Harmony classes as sugar
discussion, but it is not the only or best way, and it bites back. We
do not want to overspecify so that the abstraction leaks and you can
see the mutable, argument-ful, expensive functions under the hood.

Also the let expression

z = let (x = 2, y = x) x + y;

should desugar to exactly

z = (function(x, y) x + y)(2, x);

The reasons for these particular desugarings is this is exactly what JavaScript programmers are writing today.

So what? Programmers do what they must in a language that has not
evolved in nine years.

I cited Stockholm Syndrome the other day. It's a problem in JS-land.
Users happy with closures for everything should go on using them.
These are not the self-appointed victims I mean. But to say that let
and block scope (and possibly other binding facilities not
desugarable to ES1-3.x) must be spelled out exactly this way is
bogus. Besides the leaks and inefficiencies, it makes a virtue of
necessity, or of a vice.

# David-Sarah Hopwood (17 years ago)

Ingvar von Schoultz wrote:

The problem with "let" isn't inexactness or incompleteness, it's that it's completely off the mark and unrelated, when read as plain English.

It's not supposed to be related to plain English; it's supposed to be related to mathematical English usage ("let x be ...").

# Peter Hall (17 years ago)

I think the question being posed by the anti-let camp really is, given
that on the surface both var and let do the same thing (declare a
variable), does the choice 'let' help describe how those keywords
differ in behaviour?

Peter

# Brendan Eich (17 years ago)

On Aug 21, 2008, at 10:53 AM, Peter Hall wrote:

I think the question being posed by the anti-let camp really is, given that on the surface both var and let do the same thing (declare a variable), does the choice 'let' help describe how those keywords differ in behaviour?

Does var? Some find for strange (not if you think of Math, as David- Sarah pointed out for let: for all ...).

No word is going to spell out what's going on by itself. Text does
not interpret itself. 'local' is not self-describing, and it can be a
misnomer.

The tradition behind let is strong, and it has brevity on its side
too as Richard Cornford pointed out.

But I'm dismayed that we're still coloring the shed. The real issues
are the binding semantics: hoisting, forward refs, etc. Jon Z made a
bold proposal there.

# Waldemar Horwat (17 years ago)

Brendan Eich wrote:

On Aug 21, 2008, at 8:21 AM, Peter Michaux wrote:

I think that the let statement

let (x = 2, y = x) { print(y); }

should desugar to exactly

(function(x, y) { print(y); })(2, x)

We've been over this. What if you replace print(y) with return y?

I had slides in 2006 talks on ES4 that showed how folks use closures
for everything, including scoped statements and scoped expressions.
That does not mean everything should desugar to function applications.

Besides the return issue, there are break and continue to consider,
and the arguments object.

... and 'this' and 'var' and legacy arguments on function objects ...

Waldemar
# Mark S. Miller (17 years ago)

On Thu, Aug 21, 2008 at 9:27 AM, Brendan Eich <brendan at mozilla.org> wrote:

Besides the return issue, there are break and continue to consider, and the arguments object.

And "this". At least the "this" issue can be handled by a moderately more complex desugaring without renaming: If the original mentions "this" freely, then the desugared closure would be invoked with ".call(this, ...)" rather than "(...)". But the other issues cannot be so pleasantly handled. Closures in Scheme and Smalltalk do not have any of these problems. It is a shame that closures in JavaScript are not as well behaved, but that is the situation we have to live with.

Desugaring may seem all the rage from the Harmony classes as sugar discussion, but it is not the only or best way, and it bites back. We do not want to overspecify so that the abstraction leaks and you can see the mutable, argument-ful, expensive functions under the hood.

I think we need to take these on a case by case basis. When a desugaring into functions doesn't leak or bite back, then we should prefer to specify things this way rather than introduce new primitive semantics.

z = let (x = 2, y = x) x + y;

should desugar to exactly

z = (function(x, y) x + y)(2, x);

The reasons for these particular desugarings is this is exactly what JavaScript programmers are writing today.

So what? Programmers do what they must in a language that has not evolved in nine years.

But there should not have been anything wrong with the semantics of

z = (function(x, y) x + y)(2, x);

to define the semantics of z = let (x = 2, y = x) x + y;

Since we're talking about expressions here, return/break/continue are not problems. "this" is a fixable problem as above. "arguments" is likely to be removed in ES-Harmony strict mode. The function-value itself never becomes reachable by other means, so its identity and mutability are not observable. So defining the semantics of let expressions by this desugaring looks not-very-leaky.

Btw, Lars pointed out that since ES-Harmony has optional parameters with defaults, we could avoid textually separating the args from the parameters. Combining suggestions:

z = (function(x=2, y=x) x+y)();
// since the original body didn't mention "this"

or

z = (function(x=2, y=x) foo(this)+x+y).call(this);
// if the original body were "foo(this)+x+y"

It has been suggested (perhaps by me -- I really don't remember) that optional and rest parameters should preclude use of "arguments" even in non-strict mode. If that were the case, then the only remaining leakiness of the above expansion is that it would prohibit use of "arguments" in the original let-body expression.

Btw, none of my remarks above should be taken as an endorsement of adding either the let statement or the let expression to the language. I am in favor of let-as-the-new-var with letrec semantics. As for these others, I am skeptical as to whether they are worth their weight -- even as pure sugar.

I cited Stockholm Syndrome the other day. It's a problem in JS-land. Users happy with closures for everything should go on using them. These are not the self-appointed victims I mean. But to say that let and block scope (and possibly other binding facilities not desugarable to ES1-3.x) must be spelled out exactly this way is bogus.

I agree that "must" is too strong, but "bogus" seems too harsh. When definition by desugaring is adequate, it should be preferred. When it isn't adequate, we should examine whether there are other ways of repairing the situation without expanding the desugared semantics of the language.

Besides the leaks and inefficiencies, it makes a virtue of necessity, or of a vice.

JavaScript's semantics are already too large and complicated. Further expansion of these semantics should be considered a vice, even it if will sometimes be a necessity. I don't think we're really disagreeing here about substantive points, but value-laden words also convey an emphasis. I come at these issues with a different emphasis.

# Waldemar Horwat (17 years ago)

Brendan Eich wrote:

The tradition behind let is strong, and it has brevity on its side
too as Richard Cornford pointed out.

But I'm dismayed that we're still coloring the shed. The real issues
are the binding semantics: hoisting, forward refs, etc. Jon Z made a
bold proposal there.

/be

I agree. Barring significant new evidence, the choice of word is not worth debating further.

Waldemar
# Mark S. Miller (17 years ago)

On Thu, Aug 21, 2008 at 11:10 AM, Waldemar Horwat <waldemar at google.com> wrote:

Besides the return issue, there are break and continue to consider, and the arguments object.

... and 'this' and 'var' and legacy arguments on function objects ...

Oh yes, I'd forgotten about 'var'. How ironic, given the topic of the thread. Fortunately, it is also not an issue for the let expression.

# Ingvar von Schoultz (17 years ago)

Peter Hall wrote:

I think the question being posed by the anti-let camp really is, given
that on the surface both var and let do the same thing (declare a
variable), does the choice 'let' help describe how those keywords
differ in behaviour?

Exactly!

However I agree with Brendan about not bike-shedding too much. Although I give this much more importance than he does, I do think that we've discussed it enough for now. There are other interesting topics on the table.

Except I just can't resist adding the following...

David-Sarah Hopwood wrote:

It's not supposed to be related to plain English; it's supposed to be related to mathematical English usage ("let x be ...").

In mathematical jargon, "let x be 5" does not mean "make x visible only between these two braces."

In mathematical jargon it means "make x have the value 5".

# Mike Cowlishaw (17 years ago)

<yawn> The 'spelling' of keywords has probably eaten more

programming-language-committee bandwidth than any other topic. But it really is only worth discussing at the start of the design of a language, where one puts principles in place (such as 'abbreviations only shorten and never remove vowels' [so they can be looked up in dictionaries by non-native speakers] or 'there are no reserved keywords' [so the language can be extended easily], or 'we are following the Java-Algol-C-BASIC-PL/I precedent').

For ES, the choice of keywords should probably follow the 'gut-feeling' of the original designer ... that way, the design has the best chance of remaining coherent.

ANSI REXX (X3.274-1996) managed to avoid this particular distraction. The only time that that committee came close to blows was over the discussion on how to indent the code in the standard. (There is a lot of code in the standard, because the language is defined as a non-circular implementation of itself, based on a very small set of primitives.) :-)

bit.ly/mfc

Unless stated otherwise above: IBM United Kingdom Limited - Registered in England and Wales with number 741598. Registered office: PO Box 41, North Harbour, Portsmouth, Hampshire PO6 3AU

# Peter Michaux (17 years ago)

On Thu, Aug 21, 2008 at 9:27 AM, Brendan Eich <brendan at mozilla.org> wrote:

On Aug 21, 2008, at 8:21 AM, Peter Michaux wrote:

I think that the let statement

let (x = 2, y = x) { print(y); }

should desugar to exactly

(function(x, y) { print(y); })(2, x)

We've been over this. What if you replace print(y) with return y?

Then we can do the following

z = let (x = 2, y = x) { return y; }

which is handy in a language that constantly deals with side effects. There is no Scheme "begin" or Lisp "progn" expression being proposed which means we will have to write the following pattern

var y; let (x = 34) { // side effects lines document.getElementById('foo').className="n"+x; // "return" y y = x+4; }

where it would be nice to write something like

var y = let (x = 34) begin { document.getElementById('foo').className="n"+x; x+4; }

or as suggested by the desugaring above

var y = let (x = 34) { document.getElementById('foo').className="n"+x; return x+4; }

I had slides in 2006 talks on ES4 that showed how folks use closures for everything, including scoped statements and scoped expressions. That does not mean everything should desugar to function applications.

No it does not mean that; however, JavaScript functions have been shown to be the saving grace of the language and I think it makes sense to cling to them with all of our programming might. (You may cite Stockholm Syndrome again and that I have it so don't know it but there is nothing I can do about that.) Functions are well understood quantities. Making functions as strong/useful as possible (e.g. adding tail call elimination) and then adding some sugar to existing common patterns (i.e. like having some built-in macros to ease boilerplate pain) makes a lot of sense to me. High quality functions and sugar built on them is a safe bet/insurance policy.

Besides the return issue, there are break and continue to consider, and the arguments object.

Break and continue would be syntax errors.

I'd expect the arguments object inside a let block to refer to to the let block's arguments. The arguments object will be less of an issue with rest arguments.

"this" has been mentioned in other posts but it is "fixed" with the proposal that inner functions have their outer function's this value.

Desugaring may seem all the rage from the Harmony classes as sugar discussion, but it is not the only or best way, and it bites back. We do not want to overspecify so that the abstraction leaks and you can see the mutable, argument-ful, expensive functions under the hood.

Also the let expression

z = let (x = 2, y = x) x + y;

should desugar to exactly

z = (function(x, y) x + y)(2, x);

The reasons for these particular desugarings is this is exactly what JavaScript programmers are writing today.

So what?

Maybe "so what?" but it makes it easy to explain what let is: simple sugar for an existing pattern.

Programmers do what they must in a language that has not evolved in nine years.

True but by the same token as some of your arguments, that doesn't make current practices wrong either.

I cited Stockholm Syndrome the other day. It's a problem in JS-land. Users happy with closures for everything should go on using them. These are not the self-appointed victims I mean. But to say that let and block scope (and possibly other binding facilities not desugarable to ES1-3.x) must be spelled out exactly this way is bogus.

I'm not suggesting the "must be" but that it seems sensible that they are.

Besides the leaks and inefficiencies, it makes a virtue of necessity, or of a vice.

Peter

# Jon Zeppieri (17 years ago)

On Thu, Aug 21, 2008 at 4:33 PM, Peter Michaux <petermichaux at gmail.com> wrote:

which is handy in a language that constantly deals with side effects. There is no Scheme "begin" or Lisp "progn" expression being proposed which means we will have to write the following pattern

var y; let (x = 34) { // side effects lines document.getElementById('foo').className="n"+x; // "return" y y = x+4; }

where it would be nice to write something like

var y = let (x = 34) begin { document.getElementById('foo').className="n"+x; x+4; }

There are comma expressions in ES, so using a let expression:

var y = let (x = 34) document.getElementById('foo').className="n"+x, x+4;

... would do what you want, I believe.

# Brendan Eich (17 years ago)

On Aug 21, 2008, at 1:33 PM, Peter Michaux wrote:

We've been over this. What if you replace print(y) with return y?

Then we can do the following

z = let (x = 2, y = x) { return y; }

Anyone who knows JS sees return and looks for the nearest enclosing
function form. Breaking this cognitive model looks like a mistake,
therefore the let proposal for ES4 and the implementation in JS1.7 do
not change the meaning of return.

Different semantics should have distinct syntax; similarity or
symmetry may motivate reuse of syntactic forms or ideas. Here, there
is no function to return y from, to be assigned to z. You could say
"let desugars", but it doesn't say what it means.

which is handy in a language that constantly deals with side effects. There is no Scheme "begin" or Lisp "progn" expression being proposed which means we will have to write the following pattern

var y; let (x = 34) { // side effects lines document.getElementById('foo').className="n"+x; // "return" y y = x+4; }

Indeed, this looks like a case where an immediately applied function
expression is the right tool.

where it would be nice to write something like

var y = let (x = 34) begin { document.getElementById('foo').className="n"+x; x+4; }

or as suggested by the desugaring above

var y = let (x = 34) { document.getElementById('foo').className="n"+x; return x+4; }

I wish I have flouted Netscape management's "make it look like Java"
directive a bit harder, and reverted to BCPL from C as the ancestor:
everything's an expression. But that ship has sailed.

On es-discuss we've had some proposals for new syntax to abruptly
complete evaluation of an expression with its result, and to
"expression-ize" statements. But these have not found much favor.

You can't go home again, truly.

) Functions are well understood quantities. Making functions as strong/useful as possible (e.g. adding tail call elimination) and then adding some sugar to existing common patterns (i.e. like having some built-in macros to ease boilerplate pain) makes a lot of sense to me. High quality functions and sugar built on them is a safe bet/insurance policy.

This all sounds great, but in order to reform functions, to recover
their Schemeish better form, we need incompatible changes. A strict
mode or similar is a big hammer, which does not compose as well as
one would like. The greater its distance from the standard mode, the
higher the migration tax. New syntax could do the trick, and indeed
classes as sugar are viewed by the committee as appropriate syntax
for higher-integrity constructor functions.

"Functions are well understood", but all of us had to remind
ourselves (and one another, apparently :-/) of the problem children:
arguments, this, var, function in block extensions, etc.

Anyway, the point at issue here concerns the other let forms, let
blocks and let expressions, and whether they ought to be other ways
of writing immediately applied function expressions. You don't gain
safety, or insure against mistakes, just by desugaring this way. You
have to address the usability or cognitive problems of return, etc.,
changing where control flow goes. You have to do something beyond the
desugaring to make arguments, this, etc. work

"this" has been mentioned in other posts but it is "fixed" with the proposal that inner functions have their outer function's this value.

No, it's not. That proposal was backward-incompatible, and AFAIK not
on the table for Harmony or in ES3.1. The most being done there,
again if my memory serves, is for strict mode to pass undefined for
this instead of null, which then would be replaced by the global object.

BTW, there are use-cases for break and continue in let blocks, which
you break simply to provide another way to write function
expressions, immediately applied. That does violence for no necessary
reason.

The reasons for these particular desugarings is this is exactly what JavaScript programmers are writing today.

So what?

Maybe "so what?" but it makes it easy to explain what let is: simple sugar for an existing pattern.

The pattern doesn't need sugar, or in this case, vinegar that
confuses where return goes, what |this| means, etc.

Programmers do what they must in a language that has not evolved in nine years.

True but by the same token as some of your arguments, that doesn't make current practices wrong either.

I never said it did. I'm saying your proposal to reinvent functions
using let syntax is wrong, however. :-|

I cited Stockholm Syndrome the other day. It's a problem in JS- land. Users happy with closures for everything should go on using them. These
are not the self-appointed victims I mean. But to say that let and block
scope (and possibly other binding facilities not desugarable to ES1-3.x) must be spelled out exactly this way is bogus.

I'm not suggesting the "must be" but that it seems sensible that
they are.

I don't know how to define "sensible".

Desugaring is a good exercise to avoid growing runtime semantics in
the spec or any language model without needing to.

OTOH, if you can't say something new with old syntax, where it's
important to be able to say something new (e.g., lexical scope only
here down; generate a new name not equal to any string for use
accessing properties or variables), and where the new something is
not a library function, then add new syntax along with the semantics.

# Ingvar von Schoultz (17 years ago)

Jon Zeppieri wrote:

Just to be clear about this: my comments were directed at the claim that "let is the new var." It seemed that one of the design goals of the let declaration was that it should be a drop-in replacement for var, only with block scoping. That would require (in Scheme terms) letrec*-like semantics. Given

let x = 2, y = x * 2;

... the let-bound x would have to be visible to y's initializer.

Yes, as a simple javascripter without Scheme experience, I prefer that everything above be in the same scope. This is simple, it's free of intricacies that I feel don't add value. And I'd prefer that all uses of let follow this rule, everything in the same scope:

 let (x = 2, y = x * 2) {...}

 z = let (x = 2, y = x * 2) y;

let fn = function(n) { if (n === 0) return 1; else return n * fn(n - 1); };

... the 'fn' on the right hand side would refer to the let-bound value (and not to something in the enclosing scope).

Yes indeed. If instead left and right side are in different scopes, it seems the only "useful" thing that this adds is the ability to give the same name different meanings in adjacent code. But that's error-prone. Suppose you're reading someone else's code:

 var a = 0; // Say you have noticed this declaration.
 // Several lines of code.
 for (let a = a; a < 10; a++)
 {   // Several lines of code.
     let x = a; // Have you noticed the change in meaning?
 }
 let y = a; // Are you aware that a is unaffected by the loop?

Having left and right in the same scope is simpler, more intuitive and more useful, in my view.

So, here is a suggestion that, I am sure, no one but me will like: drop let declarations and only include let statements and expressions. Give them let semantics. Maybe this is only true of me, but if let statements were in the language, I would never use let declarations, anyway. The advantage of the statement and expression forms is that they make the scope of the let-bound variables explicit.

For very small and simple projects it's great that JavaScript lets you sprinkle your declarations all over the code, with redundant repetitions if you like. Block scope should be available also with this usage pattern, in my view.

However, inside the block of a let statement, and its nested blocks, all let and var declarations might be forbidden. The idea being that if you use this construct you want all your declarations at the top of your blocks, and no surprises inside.

Let statements might also enable throwing an error on undeclared names.

While we're speaking of radical proposals, here's another one: If let is used anywhere in a block (any type of block), then forbid var in that block and all its nested blocks. And if var is used, forbid let. Allow both only in the global scope.

I think the let/var duality will be a source of much confusion. Every project will want to use one or the other, not both mixed.

That's one reason why I proposed a {{better block}} with let disabled inside. One behavior, less confusion.

# Mark S. Miller (17 years ago)

On Thu, Aug 21, 2008 at 3:07 PM, Brendan Eich <brendan at mozilla.org> wrote:

[...] A strict mode or similar [...]. The greater its distance from the standard mode,

A nit: Please let's start referring to the opposite of strict mode as non-strict mode. Once these become official, they will both be standard.

# Brendan Eich (17 years ago)

On Aug 21, 2008, at 6:54 PM, Mark S. Miller wrote:

On Thu, Aug 21, 2008 at 3:07 PM, Brendan Eich <brendan at mozilla.org>
wrote:

[...] A strict mode or similar [...]. The greater its distance
from the standard mode,

A nit: Please let's start referring to the opposite of strict mode as non-strict mode. Once these become official, they will both be standard.

Ok!

# Peter Michaux (17 years ago)

On Thu, Aug 21, 2008 at 1:45 PM, Jon Zeppieri <jaz at bu.edu> wrote:

On Thu, Aug 21, 2008 at 4:33 PM, Peter Michaux <petermichaux at gmail.com> wrote:

which is handy in a language that constantly deals with side effects. There is no Scheme "begin" or Lisp "progn" expression being proposed which means we will have to write the following pattern

var y; let (x = 34) { // side effects lines document.getElementById('foo').className="n"+x; // "return" y y = x+4; }

where it would be nice to write something like

var y = let (x = 34) begin { document.getElementById('foo').className="n"+x; x+4; }

There are comma expressions in ES, so using a let expression:

var y = let (x = 34) document.getElementById('foo').className="n"+x, x+4;

... would do what you want, I believe.

That does seem to cover the use case I was describing.

Thanks.

Peter

# Jon Zeppieri (17 years ago)

On Thu, Aug 21, 2008 at 7:19 PM, Ingvar von Schoultz <ingvar-v-s at comhem.se> wrote:

Jon Zeppieri wrote:

let x = 2, y = x * 2;

... the let-bound x would have to be visible to y's initializer.

(Actually, I left out the '' part of 'letrec' here, so: the let-bound variables would also have to be initialized left to right, just as with a var declaration. I also didn't mention hoisting, which is relevant below.)

[snip]

... the 'fn' on the right hand side would refer to the let-bound value (and not to something in the enclosing scope).

Yes indeed. If instead left and right side are in different scopes, it seems the only "useful" thing that this adds is the ability to give the same name different meanings in adjacent code. But that's error-prone. Suppose you're reading someone else's code:

var a = 0; // Say you have noticed this declaration. // Several lines of code. for (let a = a; a < 10; a++) { // Several lines of code. let x = a; // Have you noticed the change in meaning? } let y = a; // Are you aware that a is unaffected by the loop?

I don't find this confusing, at all. I think it could become confusing if there were redundant declarations of the same variable, as allowed by var.

Having left and right in the same scope is simpler, more intuitive and more useful, in my view.

For a moment I thought you might be right about the "more useful" part. It would be a problem if the let form didn't allow the binding of recursive functions (assuming that we do not want separate 'let' and 'letrec' forms in the language). But I think function expressions can supply their own names, right? So, even a non-recursive let form would allow:

let (fn = function fact(n) { ... fact(n - 1); }) { ... }

(Also the spec-formerly-known-as-ES4 had a 'this function' expression that could be used to achieve the same effect.)

Non-recursive bindings are sometimes useful (particularly for simple code generation). Left-to-right evaluation of the bindings is often useful...

So, here is a suggestion that, I am sure, no one but me will like: drop let declarations and only include let statements and expressions. Give them let semantics. Maybe this is only true of me, but if let statements were in the language, I would never use let declarations, anyway. The advantage of the statement and expression forms is that they make the scope of the let-bound variables explicit.

After thinking about this a bit more, I don't know what single binding semantics to prefer:

let: closest to the immediate function expression + application pattern in common use let*: like let, but with left-to-right evaluation letrec*: closest to current 'var' behavior

For very small and simple projects it's great that JavaScript lets you sprinkle your declarations all over the code, with redundant repetitions if you like. Block scope should be available also with this usage pattern, in my view.

I do know, however, that I don't like this.

I think you, Ingvar, are the lone champion of redundant variable declarations.

I'm not sure who the champions of var hoisting are. (In another thread, Brendan referred to hoisting as a wart.)

So, the only 'let' form that the working group has, in principle, agreed to add to the language is the one that allows redundant declarations and hoists? Consistency is not an absolute virtue.

[snip]

Let statements might also enable throwing an error on undeclared names.

I can't imagine what you have in mind here.

While we're speaking of radical proposals, here's another one: If let is used anywhere in a block (any type of block), then forbid var in that block and all its nested blocks. And if var is used, forbid let. Allow both only in the global scope.

This complicates, rather than simplifies, the language. Compositionality is good.

# Yuh-Ruey Chen (17 years ago)

Jon Zeppieri wrote:

For very small and simple projects it's great that JavaScript lets you sprinkle your declarations all over the code, with redundant repetitions if you like. Block scope should be available also with this usage pattern, in my view.

I do know, however, that I don't like this.

I think you, Ingvar, are the lone champion of redundant variable declarations.

Actually, I'm pretty sympathetic to redundant variable declarations, because cut/copy/pasting around code often requires tedious finessing of declarations.

With that said, I wish variables did not require |var| declarations and were just local by default ala Python. It would solve this issue and improve overall security to boot (from dumb coder mistakes), but unfortunately it's too late to change :(

# Breton Slivka (17 years ago)

On Fri, Aug 22, 2008 at 1:21 AM, Peter Michaux <petermichaux at gmail.com> wrote:

On Thu, Aug 21, 2008 at 6:31 AM, Brendan Eich <brendan at mozilla.org> wrote:

More helpful would be comments on the utility of let blocks (a.k.a. let statements) and let expressions. Also comparisons to the several let forms in Scheme (Jon Z. posted something a while ago on this topic).

Hello, I am a javascript end-user (and occasional abuser). I've been following this fascinating conversation, and I figure since Brenden is polling for comments, I thought I would throw mine in. Let expressions and let statements seem like they might help speed the writing of some kinds of code, but it looks to me like they complicate reading code back. In the case of let statements, as I understand it, the current proposal, and how let works in firefox is that

let (x = 2, y = x) { print(y); }

"desugars" to

{ let x = 2, y = x; print(y); }

This makes sense to me, and I could possibly even be convinced that the first form organizes code a bit better, by keeping all the variables in one place, and distinct from the code that operates on those variables.

The let expression on the other hand

z = let (x = 2, y = x) x + y;

it spooks me out because it's a language construct that uses parentheses being used kind of like an operator. Similar things can be done with the if statement, and that usage can easily lead to bugs. Javascript 1.8's similar treatment of function spooks me in the same way- because it suddenly becomes more difficult for me as a reader to determine what code is part of the function, or the let statement, or the if statement, and which parts are not. At least if there are { } braces then it's visually obvious where the effect starts and where it ends.

Though I suppose for some, saving two keystrokes is important.

I was reading the resulting ticket a few days ago.

bugs.ecmascript.org/ticket/375

I think that the let statement

let (x = 2, y = x) { print(y); }

should desugar to exactly

(function(x, y) { print(y); })(2, x)

Also the let expression

z = let (x = 2, y = x) x + y;

should desugar to exactly

z = (function(x, y) x + y)(2, x);

I think that intruducing function semantics to the world of "let" would cause undue confusion, since what we are essentially talking about is a drop in replacement for "var", plus some additional syntax to make block scopes easier to create. As has already been covered by brendan, functions bring with them a boatload of baggage that I don't necessarily want in just a simple block scope. This is especially important considering that javascript closures are actually quite an advanced subject. It would be much easier to explain the let statement on its own terms, than to try to explain it in terms of everything that a javascript function does.

But at the same time, I can agree that I woudln't mind some kind of syntactic sugar for those function patterns. I just don't think "let" Is the right sugar. I feel that there could be much less verbose ways of declaring a function in place than what is currently on offer. It is quite common to declare a function as a callback, and define it in place as a parameter to another function, and the current syntax for doing that is quite bulky. In addition, the syntax for declaring a function, and calling it in place is bulky as well. (though for many of the cases where you'd need to do it, a let statement without the function baggage would work just as well).

When I saw the notes for javascript 1.8 I was quite excited about syntactic sugar for function declarations, but was quite dissappointed by what was delivered. I've already sounded off about my anxiety from function (a, b) a+b;, What I was expecting, and would have prefered was something more along the lines of (a, b){ a+b; }; or even fn(a, b){ a+b; }; it's really the "function" keyword, which cannot even be properly aliased, that really gets to me. Especially when I just need to quickly define a function parameter in place.

Though if I supposed that let statements, or some other construct implemented the real lambdas that Brendan has been mentioning, I would be just as happy with those, if it could make my code a bit less bulky, and more readable.

# Brendan Eich (17 years ago)

On Aug 21, 2008, at 10:10 PM, Breton Slivka wrote:

In the case of let statements, as I understand it, the current proposal, and how let works in firefox is that

let (x = 2, y = x) { print(y); }

"desugars" to

{ let x = 2, y = x; print(y); }

No, because in the latter, as for var in a program or function body,
let x is hoisted to the top of the block, so y's initializer x is not
the value of the outer x, but the undefined initial value of the
hoisted inner x.

So let statements really are different from let declarations in blocks.

New let forms may look spooky or useful, depending on your language
background. Schemers tend not to be spooked; folks who started with
JS, Java, C++ or C may bolt ;-).

# Ingvar von Schoultz (17 years ago)

Mark S. Miller wrote:

A nit: Please let's start referring to the opposite of strict mode as non-strict mode. Once these become official, they will both be standard.

The pragma "use subset standard" suffers from the same problem, plus it will cause pointy-haired bosses looking over your shoulder to insist that you write "use subset standard" because Standard Is Good.

How about:

 use subset strict
 use subset relaxed
# Ingvar von Schoultz (17 years ago)

Jon Zeppieri wrote:

Suppose you're reading someone else's code:

var a = 0; // Say you have noticed this declaration. // Several lines of code. for (let a = a; a < 10; a++) { // Several lines of code. let x = a; // Have you noticed the change in meaning? } let y = a; // Are you aware that a is unaffected by the loop?

I don't find this confusing, at all. I think it could become confusing if there were redundant declarations of the same variable, as allowed by var.

Obviously the confusion occurs only if you miss |let a=a|, not if you see it. Program maintenance becomes more expensive when you must painstakingly look for things like |let a=a| everywhere.

Non-recursive bindings are sometimes useful (particularly for simple code generation).

It seems trivial to use different names. I really don't get this. Is there a shortage of letters?

After thinking about this a bit more, I don't know what single binding semantics to prefer:

let: closest to the immediate function expression + application pattern in common use let*: like let, but with left-to-right evaluation letrec*: closest to current 'var' behavior

If it's like var, people can re-use their knowledge about var. Let them spend their learning time on more useful things than tiny scoping intricacies.

For very small and simple projects it's great that JavaScript lets you sprinkle your declarations all over the code, with redundant repetitions if you like. Block scope should be available also with this usage pattern, in my view.

I do know, however, that I don't like this.

I think you, Ingvar, are the lone champion of redundant variable declarations.

Earlier I declared variables only once, and would sometimes forget. The bugs cost time. With var on every initialization the problem disappears.

As a result, the lack of var has become a warning that I notice very clearly. Do I really want global here? I'd prefer an "outer" declaration, but have to use the lack of var instead.

I'm not sure who the champions of var hoisting are. (In another thread, Brendan referred to hoisting as a wart.)

That's me too, but it was combined with things that made hoisting all but disappear. Unfortunately my explanations were bad, and the proposal drowned under claims that I was instead proposing something very different and very unworkable that I never intended, and persistent attacks against this strawman.

I did learn a lot about how to explain better, so maybe I could try again and get across this time. The real proposal was beautiful simplicity both in usage and implementation.

Let statements might also enable throwing an error on undeclared names. I can't imagine what you have in mind here.

 let (a = 3)
 {   x = 5;
 }

If you put |let (a = 3)| above your block, this might tell the compiler that you want everything neatly declared at the top, and therefore want an error thrown at the undeclared x. A strict mode regarding declarations.

# Jon Zeppieri (17 years ago)

On Fri, Aug 22, 2008 at 10:22 AM, Ingvar von Schoultz <ingvar-v-s at comhem.se> wrote:

let (a = 3) { x = 5; }

If you put |let (a = 3)| above your block, this might tell the compiler that you want everything neatly declared at the top, and therefore want an error thrown at the undeclared x. A strict mode regarding declarations.

var x;

let (a = 3) { ... x = 5 * a; ... }

This is perfectly reasonable code. If the assignment throws, the language is broken. Now, if you erase the "var x" line, the only difference, semantically, is that the assignment is to a property of the global object. Not great style, but I'd still expect it to work.

# Jon Zeppieri (17 years ago)

On Fri, Aug 22, 2008 at 2:22 AM, Brendan Eich <brendan at mozilla.org> wrote:

On Aug 21, 2008, at 10:10 PM, Breton Slivka wrote:

In the case of let statements, as I understand it, the current proposal, and how let works in firefox is that

let (x = 2, y = x) { print(y); }

"desugars" to

{ let x = 2, y = x; print(y); }

No, because in the latter, as for var in a program or function body, let x is hoisted to the top of the block, so y's initializer x is not the value of the outer x, but the undefined initial value of the hoisted inner x.

So let statements really are different from let declarations in blocks.

I didn't know that JS 1.7 already implements different binding semantics for let declarations on one hand and let statements and expressions on the other. That's odd. I can see why you might want different semantics, but using the same keyword in both cases is a bit gross.

It might actually be better to add separate let and letrec keywords... except that the meaning of let declarations (as opposed, I mean, to letrec declarations) might be strange...

var x = 0;

{ ... let x = 10; ... let y = x + 5;

}

printf

# Fergus Cooney (17 years ago)

I'm sorry to be putting in my two cents on the "let" debate after so many posts and people getting tired of it but I hope that my contribution is original and useful.

Sam Ruby wrote:

Perl uses "my". Short. Implies scope.

It's delightfully short and it does imply scope but, for me at least, I've hated "my" ever since MyComputer. It's always struck me as somewhat childish. My crayon, my computer, my variable. I'm sure I'd get used to it but it does make me cringe. (My cringe!)

Jon Zeppieri wrote:

Allen's BASIC point is a good one, and all I can muster in response is a (mostly) tongue-in-cheek reply: BASIC programmers who go on to learn other languages first find it necessary to unlearn BASIC.

I never liked "let" in Basic either. When it became optional it disappeared from my programs and has never been missed.

.

I like Ingvar's "local" but I understand the point about "local" already being part of the meaning of "var".

I propose another name for consideration and that is "here".

function foo (arg) { var x = 1; if (arg.iffy_decision == 1) { here x = arg.and_now_for(); : : } else { here x = arg.something_completely_different(); : : } }

"Here" has no precendence in Basic or Lisp to confuse people coming from those domains. It's also not mathematical - and that's a good thing.

Ingvar von Schoultz wrote:

The problem with "let" isn't inexactness or incompleteness, it's that it's completely off the mark and unrelated, when read as plain English.

David-Sarah Hopwood wrote:

It's not supposed to be related to plain English; it's supposed to be related to mathematical English usage ("let x be ...").

I don't agree. I don't think that "let" being mathematical gives any advantage. I expect that for many scripters, if not most, programming is more about logic, structure and meaning than it is about maths. "Here" is meaningful and unambiguous.

Btw, someone's idea that [other words in the language aren't as meaningful as their use, so why bother].. that's irrelevant, surely? Is there any real reason not to pick the best fitting words wherever possible?

Richard Cornford wrote:

While "let" is the type of word that does not lend itself to being used as a variable name, "local" may have been used to name something that embodied that concept.

"Here" is similarly hard to imagine being used as a variable.

Ingvar von Schoultz wrote:

I think of |local x| as an abbreviation of |local var x|, so in the global scope I'd omit |local| and write |var x|.

I think that many would see "let x=.." as a shorthand for "let var x=.." and the "let" isn't conveying the scope aspect of its semantics, in fact in the expanded form it seems rather redundant. That's one reason why it was good when it could be from Basic programs. It was extra typing but no extra meaning.

If "here x=.." is considered as a shorthand for "here var x=.." then it gives the same meaning in both forms. In fact it's effectively a modifier on "var" which states that it should not be hoisted, and "here x =" is therefore literally a shorthand.

Brendan Eich wrote:

Keyword connotations aside, let has clear denotation in many programming languages.

I'm not sure what languages you mihgt be referring to so are these languages where the issue of scope is not as fuzzy as in javascript? If so, then "let" doesn't have to convey the semantics of scope as it is being required to in javascript.

I don't think it's worthwhile for the list to bike-shed too much when many on the TC39 committee have recently expressed support for let declarations.

I'm not sure what bike-shedding is but I hope there's room for a few ponders over "here".

Brendan Eich wrote:

But I'm dismayed that we're still coloring the shed.

Ah, I get that one better and in that case I think it's okay to be picky about what paint we use - we'll be looking at it for a long time to come.

The real issues are the binding semantics: hoisting, forward refs, etc. Jon Z made a bold proposal there.

Well, those are other real issues yet I do accept that for you guys who are juggling the whole shebang they are the real issues. Still, I hope that "here" might bring some harmony here.

.Fergus Cooney

# Fergus Cooney (17 years ago)

Just a minor note.

My oops. I had to resend my first message (after changing my subscribed email address) and somehow resending it threw away my smilies. If anyone considered me a bit abrupt at any point, and that abruptness would have been tempered by a smiley, that's where there was one! ;-)

.Fergus

# Brendan Eich (17 years ago)

On Aug 22, 2008, at 11:10 AM, Jon Zeppieri wrote:

So let statements really are different from let declarations in
blocks.

I didn't know that JS 1.7 already implements different binding semantics for let declarations on one hand and let statements and expressions on the other. That's odd.

ES4 as proposed for quite a while.

I can see why you might want different semantics, but using the same keyword in both cases is a bit gross.

The introduction of letrec as a keyword seems grosser, especially for
the mass of JS programmers.

The ES4 proposal used let (head) body as the distinguishing mark,
where body could be an expression or a block. We haven't heard
complaints about using parens instead of more or longer keywords; on
the other hand, I don't think anyone is really using the unique
capabilities of these non-hoisting binding forms (to put in the
initialiser for a binding in head the same name being bound, and have
it refer to an outer binding).

The language may not support too many binding forms. The TC39
committee probably won't. Both let and const as block-scoped bindings
in the style of var (but with use before set of a const illegal, and
with const having a mandatory initialiser even though it saves
implementations no cost) seem supported by those who spoke up at the
last meeting. let blocks and let expressions do not have solid
support in TC39.

# Ingvar von Schoultz (17 years ago)

Brendan Eich wrote:

The language may not support too many binding forms. The TC39 committee probably won't. Both let and const as block-scoped bindings in the style of var (but with use before set of a const illegal, and with const having a mandatory initialiser even though it saves implementations no cost) seem supported by those who spoke up at the last meeting.

So to convert these vars into consts...

 if (Debugging)
 {   var DatabaseName = "TestDatabase";
     var DisplayCount = 5;
     ... Ten more ...
 }
 else
 {   var DatabaseName = "RealDatabase";
     var DisplayCount = 15;
     ... Ten more ...
 }

...we'll have to write something like this?

 const
 {   DatabaseName,
     DisplayCount,
     ... Ten more ...
 } =
 Debugging ?
 {   DatabaseName: "TestDatabase",
     DisplayCount: 5,
     ... Ten more ...
 }
 :
 {   DatabaseName: "RealDatabase",
     DisplayCount: 15,
     ... Ten more ...
 };

Very often conditionals aren't that simple. It'll get ugly. The new awkwardness does makes sense in big projects, but only there.

let blocks and let expressions do not have solid support in TC39.

I have no opinion on whether let blocks and let expressions are useful, but you could make them very cheap by dropping the intricacies that make let(x=x){} refer to two different x'es:

 let (a = x) {...} desugars to {let a = x; ...}

 let (a = x) a; desugars to {let a = x; a;}

As a bonus everyone will rejoice at the lessened cognitive burden of intricacies.

Of course Schemers will find a let with these semantics confusing. Clearly it needs a different name. How about... "local"? :

# Brendan Eich (17 years ago)

On Aug 25, 2008, at 3:00 PM, Ingvar von Schoultz wrote:

...we'll have to write something like this?

 const
 {   DatabaseName,
     DisplayCount,
     ... Ten more ...
 } =
 Debugging ?
 {   DatabaseName: "TestDatabase",
     DisplayCount: 5,
     ... Ten more ...
 }
 :
 {   DatabaseName: "RealDatabase",
     DisplayCount: 15,
     ... Ten more ...
 };

Very often conditionals aren't that simple. It'll get ugly. The new awkwardness does makes sense in big projects, but only there.

Another way of looking at this is to say that const should be write
once, not necessarily initialized in the declaration. Then you could
write

const DatabaseName, DisplayCount, /* ... ten more ... */; if (Debugging) { DatabaseName = ...; } else { etc. }

This was ES4's const. At the Oslo meeting there was strong opposition
to write-once. The reasons were not clear to me (could be my fault).

Here you show a reason for write-once. The alternatives are
destructuring from a ternary (as you showed), falling back on var
(losing), or inventing some super-const binding form that escapes its
block (not in the cards).

let blocks and let expressions do not have solid support in TC39.

I have no opinion on whether let blocks and let expressions are useful, but you could make them very cheap by dropping the intricacies that make let(x=x){} refer to two different x'es:

 let (a = x) {...} desugars to {let a = x; ...}

If by "cheap" you mean easy to implement, there would be a savings to
compiler costs, but not at runtime.

 let (a = x) a; desugars to {let a = x; a;}

Sorry, no: the latter is not an expression, the former is (if you
remove the ; at the end).

As a bonus everyone will rejoice at the lessened cognitive burden of intricacies.

But then why have the let block form at all, since let declarations
are sweet enough.

The case for let expressions remains even if you eliminate the let
binding rule, since they are expressions. You'd have to invent
generalized BCPL- or Algol-68-like expression language support, which
is also not in the cards (I mentioned the idea briefly in Oslo, more
as a joke or an aside).

Of course Schemers will find a let with these semantics confusing. Clearly it needs a different name. How about... "local"? :-D

Sorry, no; please stop nagging.