revive let blocks

classic Classic list List threaded Threaded
26 messages Options
12
Reply | Threaded
Open this post in threaded view
|

revive let blocks

Kyle Simpson
I'd like to ask if there's anyone on TC39 that would be willing to champion a proposal to add the let-block (let-statement) syntax?

I currently write my block-scoped declarations as:

```js
{ let a = 2, b, c;
        // ..
}
```

I do this because I want to be in the habit of always putting my `let` declarations at the top of blocks to avoid TDZ hazards. However, Firefox has long had the alternate let-block/statement syntax, which I prefer:

```js
let (a = 2, b, c) {
        // ..
}
```

Would there be support to consider such a proposal?

Side note: I'd also be in favor of a `const (a = 2) { .. }` form, if the symmetry was appealing.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Benjamin Gruenbaum-2
Apart from complicating the engine and the grammar - what advantage does the second version have over the first one? Why do you prefer it to the first one? (Genuinely asking)

I'm also not aware of any other languages that provide this (although that's not a huge issue).

> On Jun 18, 2015, at 05:27, Kyle Simpson <[hidden email]> wrote:
>
> I'd like to ask if there's anyone on TC39 that would be willing to champion a proposal to add the let-block (let-statement) syntax?
>
> I currently write my block-scoped declarations as:
>
> ```js
> { let a = 2, b, c;
>   // ..
> }
> ```
>
> I do this because I want to be in the habit of always putting my `let` declarations at the top of blocks to avoid TDZ hazards. However, Firefox has long had the alternate let-block/statement syntax, which I prefer:
>
> ```js
> let (a = 2, b, c) {
>   // ..
> }
> ```
>
> Would there be support to consider such a proposal?
>
> Side note: I'd also be in favor of a `const (a = 2) { .. }` form, if the symmetry was appealing.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Bucaran
Another way: Instead of using `let` at all, why not creating a function and pass it your `a`, `b` and `c` as arguments.

Nowadays I try to program without explicitly declaring any variables, hence my suggestion.

```js
(function (a, b, c) {
   
}(2))
```

If you can post a more concrete example I would give you a more concrete suggestion to what I mean.

Cheers

> On Jun 18, 2015, at 9:06 PM, Benjamin Gruenbaum <[hidden email]> wrote:
>
> Apart from complicating the engine and the grammar - what advantage does the second version have over the first one? Why do you prefer it to the first one? (Genuinely asking)
>
> I'm also not aware of any other languages that provide this (although that's not a huge issue).
>
>> On Jun 18, 2015, at 05:27, Kyle Simpson <[hidden email]> wrote:
>>
>> I'd like to ask if there's anyone on TC39 that would be willing to champion a proposal to add the let-block (let-statement) syntax?
>>
>> I currently write my block-scoped declarations as:
>>
>> ```js
>> { let a = 2, b, c;
>>  // ..
>> }
>> ```
>>
>> I do this because I want to be in the habit of always putting my `let` declarations at the top of blocks to avoid TDZ hazards. However, Firefox has long had the alternate let-block/statement syntax, which I prefer:
>>
>> ```js
>> let (a = 2, b, c) {
>>  // ..
>> }
>> ```
>>
>> Would there be support to consider such a proposal?
>>
>> Side note: I'd also be in favor of a `const (a = 2) { .. }` form, if the symmetry was appealing.
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Kyle Simpson
In reply to this post by Benjamin Gruenbaum-2
> Apart from complicating the engine and the grammar

I've tried to figure out what complications it introduces. In my imperfect analysis, it hasn't seemed like much. I've written a transpiler tool[1] that finds `let (x..) { .. }` occurrences and changes them to `{ let x.. .. }`. It was pretty easy to do. I would imagine a similar technique could work for other transpilers and even the engines themselves (simple AST transformation).

I'm sure there are other/obscure issues I'm missing, but the fact that this still works in FF leads me to believe it is a tenable feature at least.

> what advantage does the second version have over the first one?

The primary advantage is that it's an explicit form that syntactically forces the main `let` declarations to the top of the block, eliminating the TDZ hazard (at least for those).

Ofc that's not to say that you can't also do other `let` declarations inside the block and shoot yourself in the foot. But at least for the main ones you're declaring for the block, it's clear and obvious what variables will exist for that block's scope by looking at the top of the block.

That notion is similar to the advantages many devs feel/felt from putting all the `var` declarations at the top of a function declaration, or locating the formal function parameters explicitly in the function declaration instead of implicitly pulling in local variable declarations from `arguments`:

```js
function foo() {
   var [a,b,c] = arguments;
   // ..
}

// vs:

function bar(a,b,c) {
   // ..
}
```
 
> Why do you prefer it to the first one?

I prefer creating explicit blocks for scope rather than implicitly hijacking existing blocks for scope. I prefer to be able to reason about my `if` block separately from a localized block of scope that may appear inside it. That's why I create the explicit `{ .. }` block to put my `let` declarations in. And that's why the next logical step is to move the `let` declarations to a syntactic form that forcibly attaches them to the block, making the purpose/intent of the block all that much clearer.


  [1] https://github.com/getify/let-er

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Kyle Simpson
In reply to this post by Bucaran
> (function (a, b, c) {
>
> }(2))

The main disadvantage of that style over the one I'm advocating for is that it visually separates the variable declaration (`a`) from its value initialization (`2`). If there's 5, 10, or more lines of code in between them, it makes it much harder to figure out the initial state of variables as they enter a "block".

Also, obviously, a function call is more heavy weight (performance wise) than a block with scoped declarations.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Herby Vojčík
In reply to this post by Benjamin Gruenbaum-2


Benjamin Gruenbaum wrote:
> Apart from complicating the engine and the grammar - what advantage does the second version have over the first one? Why do you prefer it to the first one? (Genuinely asking)
>
> I'm also not aware of any other languages that provide this (although that's not a huge issue).

IIRC, Standard ML of New Jersey had a keyword 'local' for this (but it
was long ago when I has that course in university).

Herby
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: revive let blocks

Gary Guo
In reply to this post by Kyle Simpson
Be aware that the way you utilize 'let' will be a breaking change. In ES5 and ES6
```
let(a=1) 
{
}
```
is valid and it is a call to let with one argument followed by a block. Your suggestions will turn it into a let-block. In ES6 let is considered as an identifier and the meaning is created by special syntactic grammar.

Personal idea: I consider this is unnecessary. If you consider use of block without context is ugly, use if(true) or do-while(false)

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Bucaran
In reply to this post by Kyle Simpson
I see what you mean.

I always try to favor functional-style JavaScript (creating a big expression composed
of several functions, both as arguments or declared somewhere, using recursion
instead of keeping state, not using control structures, no variables, etc), hence my
suggestion.

Performance wise you are (very probably) right, but I am willing to pay the tradeoff and
live the future now, or whenever I can :)

Another idea I find fun it’s binding this to an object with my data:

```js
function f () {
}

f.call({a:2, b, c})
```


> On Jun 18, 2015, at 9:34 PM, Kyle Simpson <[hidden email]> wrote:
>
>> (function (a, b, c) {
>>
>> }(2))
>
> The main disadvantage of that style over the one I'm advocating for is that it visually separates the variable declaration (`a`) from its value initialization (`2`). If there's 5, 10, or more lines of code in between them, it makes it much harder to figure out the initial state of variables as they enter a "block".
>
> Also, obviously, a function call is more heavy weight (performance wise) than a block with scoped declarations.
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Kyle Simpson
In reply to this post by Gary Guo
> Be aware that the way you utilize 'let' will be a breaking change. In ES5 and ES6

In addition to the fact that this feature is long since co-existing in FF and doesn't seem to have broken the web, IIUC, there was already a "breaking change" in ES6, with `let` and destructuring:

```js
let[x] = foo();
```

I believe it was deemed that the chances of that breakage being widespread were low enough to warrant the `let` feature anyway. I would postulate (though I don't have the facility to test it) that the exact function-call-and-block pattern `let(x) { .. }` would be as much or less likely to occur in legacy code than `let[x] = foo()`.

> If you consider use of block without context is ugly, use if(true) or do-while(false)

Those options are much uglier than the standalone `{ .. }` block.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: revive let blocks

Benjamin Gruenbaum
In reply to this post by Kyle Simpson
> From: Kyle Simpson <[hidden email]>
To: "[hidden email]" <[hidden email]>
Cc: 
Date: Thu, 18 Jun 2015 07:34:28 -0500
Subject: Re: revive let blocks
> > (function (a, b, c) {
> >
> > }(2))

> The main disadvantage of that style over the one I'm advocating for is that it visually separates the variable declaration (`a`) from its value initialization (`2`).

If that's the problem you can do
```js
((a = 2, b, c) => {

})();
```

And engines can optimize - but I can see the merit of explicit syntax for this.

> I prefer creating explicit blocks for scope rather than implicitly hijacking existing blocks for scope. I prefer to be able to reason about my `if` block separately from a localized block of scope that may appear inside it. That's why I create the explicit `{ .. }` block to put my `let` declarations in. And that's why the next logical step is to move the `let` declarations to a syntactic form that forcibly attaches them to the block, making the purpose/intent of the block all that much clearer.

Well, traditionally this is something we've been moving _from_ in languages - for example in C (before C99) you used to have to declare variables on the top of a scope but don't anymore.  In Pascal, you had `var` for this and this was complained about by people.

Why would a syntactic addition to the language be better than a linter here that verifies where you declared your variables? The only issue I see here where this sort of thing can be really important (and justify adding it for other cases anyway) is stack allocation in a dynamic language - but I'm not sure how that proposal looks like yet and from what I understand it'll be discussed in the July TC meeting.

If anyone could shed light on the current ideas for stack allocation that'd be great :)

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Herby Vojčík


Benjamin Gruenbaum wrote:

>  > From: Kyle Simpson <[hidden email] <mailto:[hidden email]>>
> To: "[hidden email] <mailto:[hidden email]>"
> <[hidden email] <mailto:[hidden email]>>
> Cc:
> Date: Thu, 18 Jun 2015 07:34:28 -0500
> Subject: Re: revive let blocks
>  > > (function (a, b, c) {
>  > >
>  > > }(2))
>
>  > The main disadvantage of that style over the one I'm advocating for
> is that it visually separates the variable declaration (`a`) from its
> value initialization (`2`).
>
> If that's the problem you can do
> ```js
> ((a = 2, b, c) => {
>
> })();
> ```

Well, I personally think this example is good enough and engines surely
optimize already (IIFE is here long enough so that it is optimized).

> And engines can optimize - but I can see the merit of explicit syntax
> for this.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Boris Zbarsky
In reply to this post by Kyle Simpson
On 6/18/15 9:01 AM, Kyle Simpson wrote:
> In addition to the fact that this feature is long since co-existing in FF and doesn't seem to have broken the web

Firefox doesn't ship let support on the web by default yet.  For
example, this HTML:

<script>let x = 5;</script>

will result in:

   SyntaxError: missing ; before statement

at the location of the 'x'.

You have to explicitly opt in to let support in Firefox right now via
language="javascript1.8" or similar.

That's not to say this change would break the web; just that we have no
evidence it doesn't.

-Boris
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Bradley Meck
(a=1)=>{
  console.log(a)
}()

Is less verbose than an IIFE and keeps `this` the same. Also keeps the initialization and init of the variable in the same place.

On Thu, Jun 18, 2015 at 8:54 AM, Boris Zbarsky <[hidden email]> wrote:
On 6/18/15 9:01 AM, Kyle Simpson wrote:
In addition to the fact that this feature is long since co-existing in FF and doesn't seem to have broken the web

Firefox doesn't ship let support on the web by default yet.  For example, this HTML:

<script>let x = 5;</script>

will result in:

  SyntaxError: missing ; before statement

at the location of the 'x'.

You have to explicitly opt in to let support in Firefox right now via language="javascript1.8" or similar.

That's not to say this change would break the web; just that we have no evidence it doesn't.

-Boris

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Axel Rauschmayer
On 18 Jun 2015, at 15:59 , Bradley Meck <[hidden email]> wrote:

(a=1)=>{
  console.log(a)
}()

Is less verbose than an IIFE and keeps `this` the same. Also keeps the initialization and init of the variable in the same place.

Neat trick. Caveat – you need parentheses around the arrow function:

```js
((a=1)=>{
  console.log(a)
})();
```

-- 
Dr. Axel Rauschmayer
[hidden email]
rauschma.de




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Rick Waldron
In reply to this post by Boris Zbarsky


On Thu, Jun 18, 2015 at 9:54 AM Boris Zbarsky <[hidden email]> wrote:
On 6/18/15 9:01 AM, Kyle Simpson wrote:
> In addition to the fact that this feature is long since co-existing in FF and doesn't seem to have broken the web

Firefox doesn't ship let support on the web by default yet.  For
example, this HTML:

<script>let x = 5;</script>

will result in:

   SyntaxError: missing ; before statement

at the location of the 'x'.

Strange, this works in the console, but not in a script https://i.gyazo.com/e55d26495c3fe8b01938fe1b99664682.png

 

You have to explicitly opt in to let support in Firefox right now via
language="javascript1.8" or similar.

More importantly, the only reason `let (names) {}` "co-exists" in those special opt-in versions is because `let` is not allowed as an identifier. The issue that Gary Guo pointed out is a very real breaking change for the web. 

Using language="javascript1.8" will make all of these result in SyntaxError: 

  var let = 1;
  var let = function() {};
  function let() {}
  let(1); 

Otherwise this would be ambiguous: 

  let (a) 
  {}

Adding this non-standard restriction prevented authors from using `let` as an identifier. 

I wonder if some application of `[no LineTerminator here]` might make this work? Is it worth it?

Rick

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Boris Zbarsky
On 6/18/15 11:30 AM, Rick Waldron wrote:
> Strange, this works in the console, but not in a script
> https://i.gyazo.com/e55d26495c3fe8b01938fe1b99664682.png

Yep, it's entirely possible the console opts in to let.

It also exposes some APIs that are not exposed in web pages by default
and a few other interesting things like that...  Evaluating things in
the console and in the currently loaded web page are _almost_ the same,
but not quite.

In addition, in the particular screenshot you have there the currently
loaded page is the Firefox start page, which is not exactly a normal web
page either, so may have its own interesting things going on with both
the script environment and its global.

-Boris
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Rick Waldron


On Thu, Jun 18, 2015 at 12:55 PM Boris Zbarsky <[hidden email]> wrote:
On 6/18/15 11:30 AM, Rick Waldron wrote:
> Strange, this works in the console, but not in a script
> https://i.gyazo.com/e55d26495c3fe8b01938fe1b99664682.png

Yep, it's entirely possible the console opts in to let.

It also exposes some APIs that are not exposed in web pages by default
and a few other interesting things like that...  Evaluating things in
the console and in the currently loaded web page are _almost_ the same,
but not quite.

In addition, in the particular screenshot you have there the currently
loaded page is the Firefox start page, which is not exactly a normal web
page either, so may have its own interesting things going on with both
the script environment and its global.

That's interesting, thanks for the follow up!

Rick
 

-Boris

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Kyle Simpson
In reply to this post by Kyle Simpson
Just to wrap this thread up, quoting myself from another thread:

"In any case, I won't push my proposal anymore."

----

But for posterity sake, wanted to make one last comment as to why the various suggestions for IIFE's and arrow expressions are inappropriate for the task: they change (hijack) the behavior of `return`, `break`, and `continue`. A standalone block like `{ let x = 2; .. }` or `let (x = 2) { .. }` can be placed anywhere, inside a function, loop, etc, and not hijack these types of statements.

I'll be sticking with:

```js
{ let x = 42;

    console.log("The meaning of JS: ", x);

}
```

Appreciate the various thoughtful responses.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Bucaran
Hey Kyle

True for `continue` and `break`, but maybe it’s about time we stop using these archaic control structures anyway :)

As for `return` I don’t see what’s the problem if you return your value inside the IIFE as well.

Regards


> On Jun 20, 2015, at 10:10 PM, Kyle Simpson <[hidden email]> wrote:
>
> Just to wrap this thread up, quoting myself from another thread:
>
> "In any case, I won't push my proposal anymore."
>
> ----
>
> But for posterity sake, wanted to make one last comment as to why the various suggestions for IIFE's and arrow expressions are inappropriate for the task: they change (hijack) the behavior of `return`, `break`, and `continue`. A standalone block like `{ let x = 2; .. }` or `let (x = 2) { .. }` can be placed anywhere, inside a function, loop, etc, and not hijack these types of statements.
>
> I'll be sticking with:
>
> ```js
> { let x = 42;
>
>    console.log("The meaning of JS: ", x);
>
> }
> ```
>
> Appreciate the various thoughtful responses.
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: revive let blocks

Herby Vojčík
In reply to this post by Kyle Simpson
Hello!

Though this is a kind of syntax is probably macroable, interesting idea
appeared in my mind regarding let blocks, so I would show it here, maybe
it can actually be interesting for others as well.


The idea is to use existing let statement and extending it so one can
include { ... code ... } block in place of last assignment. Hold on for
a while: this form can merge with do-expressions by using 'let', not
'do' as the keyword:

   let a = 4, b = 3; // normal let
   let { throw new Error("Throw in an expression"); } // let-expression
   let a = 4, b = 3, { a + b } // let-expression with own local lets

The third form is more or less the let-block from the PoV of reader,
even if in fact is a new do-expression using let keyword with some
let-assigment local to that block happening before.

I see a 'problem' that I can only distinguish if it is a let-statement
or let-expression at the end of it, but afaict it does not pose any real
gotchas for the compiler - it accumulates the assignment and at the
either make them let-statement and use them for the rest of enclosing
block or makes it let-expression and use them only locally.

Herby

Kyle Simpson wrote:

> Just to wrap this thread up, quoting myself from another thread:
>
> "In any case, I won't push my proposal anymore."
>
> ----
>
> But for posterity sake, wanted to make one last comment as to why the various suggestions for IIFE's and arrow expressions are inappropriate for the task: they change (hijack) the behavior of `return`, `break`, and `continue`. A standalone block like `{ let x = 2; .. }` or `let (x = 2) { .. }` can be placed anywhere, inside a function, loop, etc, and not hijack these types of statements.
>
> I'll be sticking with:
>
> ```js
> { let x = 42;
>
>      console.log("The meaning of JS: ", x);
>
> }
> ```
>
> Appreciate the various thoughtful responses.
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
12