Proposal: if variable initialization

classic Classic list List threaded Threaded
45 messages Options
123
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: if variable initialization

Isiah Meadows-2
I'm personally very much *for* this `if (var ...; cond) { ... }`
syntax. I couldn't tell you how many times I would've liked something
to that effect, since that's probably one of my biggest areas of
boilerplate.

I would also be in favor of `if (var ...) { ... }` as a shorthand that
guards `!= null` the expression result (pre-match), since that's about
90% of my use cases for it. There *is* a potential area of ambiguity
in sloppy for `if ( let [ x ] = y )`, since that would be currently
parsed as `var tmp = y; let[x] = tmp; if (tmp) { ... }`, but I doubt
breaking that would be of much web compat risk. (A similar ambiguity
existed with `for (let [`, but that break didn't cause many issues.)
-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Wed, Mar 21, 2018 at 2:47 PM, Mike Samuel <[hidden email]> wrote:

>
>
> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <[hidden email]>
> wrote:
>>
>> Because block-level scoping is a very good way to avoid certain bugs and
>> is easier to reason about. Especially when considering project successors.
>
>
> +1.  function-scoped variables in loop bodies caused tons of bugs before
> let-scoped variables and were a main motivating case.
>
> var i;
> for (i = 0; i < arr.length; ++i) {
>   f(function () { /* Do something with */ arr[i]; });
> }
>
> vs
>
> for (let i = 0; i < arr.length; ++i) {
>   f(function () { /* Do something with */ arr[i]; });
> }
>
> Yes, linters got pretty good at finding uses of closed-over variables
> modified in a loop, but the workarounds were not ideal.
>
> var i;
> for (i = 0; i < arr.length; ++i) {
>   f(function (i) { return function () { /* Do something with */ arr[i]; }
> }(i));
> }
>
> Block scoping is just better for code that uses loops, variables, and
> function expressions.
>
>
> _______________________________________________
> 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: Proposal: if variable initialization

Sebastian Malton
Sorry if I missed a message but would such an initialization be only available in the first `if` block or also in the subsequent `else if` and `else` blocks?

Sebastian Malton


  Original Message  
From: [hidden email]
Sent: March 21, 2018 6:18 PM
To: [hidden email]
Cc: [hidden email]; [hidden email]
Subject: Re: Proposal: if variable initialization

I'm personally very much *for* this `if (var ...; cond) { ... }`
syntax. I couldn't tell you how many times I would've liked something
to that effect, since that's probably one of my biggest areas of
boilerplate.

I would also be in favor of `if (var ...) { ... }` as a shorthand that
guards `!= null` the expression result (pre-match), since that's about
90% of my use cases for it. There *is* a potential area of ambiguity
in sloppy for `if ( let [ x ] = y )`, since that would be currently
parsed as `var tmp = y; let[x] = tmp; if (tmp) { ... }`, but I doubt
breaking that would be of much web compat risk. (A similar ambiguity
existed with `for (let [`, but that break didn't cause many issues.)
-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Wed, Mar 21, 2018 at 2:47 PM, Mike Samuel <[hidden email]> wrote:

>
>
> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <[hidden email]>
> wrote:
>>
>> Because block-level scoping is a very good way to avoid certain bugs and
>> is easier to reason about. Especially when considering project successors.
>
>
> +1.  function-scoped variables in loop bodies caused tons of bugs before
> let-scoped variables and were a main motivating case.
>
> var i;
> for (i = 0; i < arr.length; ++i) {
>   f(function () { /* Do something with */ arr[i]; });
> }
>
> vs
>
> for (let i = 0; i < arr.length; ++i) {
>   f(function () { /* Do something with */ arr[i]; });
> }
>
> Yes, linters got pretty good at finding uses of closed-over variables
> modified in a loop, but the workarounds were not ideal.
>
> var i;
> for (i = 0; i < arr.length; ++i) {
>   f(function (i) { return function () { /* Do something with */ arr[i]; }
> }(i));
> }
>
> Block scoping is just better for code that uses loops, variables, and
> function expressions.
>
>
> _______________________________________________
> 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: Proposal: if variable initialization

Isiah Meadows-2
My implication was that it'd only be available in the `if` (if
declared with `let`/`const`).
-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Wed, Mar 21, 2018 at 6:25 PM, Sebastian Malton <[hidden email]> wrote:

> Sorry if I missed a message but would such an initialization be only available in the first `if` block or also in the subsequent `else if` and `else` blocks?
>
> Sebastian Malton
>
>
>   Original Message
> From: [hidden email]
> Sent: March 21, 2018 6:18 PM
> To: [hidden email]
> Cc: [hidden email]; [hidden email]
> Subject: Re: Proposal: if variable initialization
>
> I'm personally very much *for* this `if (var ...; cond) { ... }`
> syntax. I couldn't tell you how many times I would've liked something
> to that effect, since that's probably one of my biggest areas of
> boilerplate.
>
> I would also be in favor of `if (var ...) { ... }` as a shorthand that
> guards `!= null` the expression result (pre-match), since that's about
> 90% of my use cases for it. There *is* a potential area of ambiguity
> in sloppy for `if ( let [ x ] = y )`, since that would be currently
> parsed as `var tmp = y; let[x] = tmp; if (tmp) { ... }`, but I doubt
> breaking that would be of much web compat risk. (A similar ambiguity
> existed with `for (let [`, but that break didn't cause many issues.)
> -----
>
> Isiah Meadows
> [hidden email]
>
> Looking for web consulting? Or a new website?
> Send me an email and we can get started.
> www.isiahmeadows.com
>
>
> On Wed, Mar 21, 2018 at 2:47 PM, Mike Samuel <[hidden email]> wrote:
>>
>>
>> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <[hidden email]>
>> wrote:
>>>
>>> Because block-level scoping is a very good way to avoid certain bugs and
>>> is easier to reason about. Especially when considering project successors.
>>
>>
>> +1.  function-scoped variables in loop bodies caused tons of bugs before
>> let-scoped variables and were a main motivating case.
>>
>> var i;
>> for (i = 0; i < arr.length; ++i) {
>>   f(function () { /* Do something with */ arr[i]; });
>> }
>>
>> vs
>>
>> for (let i = 0; i < arr.length; ++i) {
>>   f(function () { /* Do something with */ arr[i]; });
>> }
>>
>> Yes, linters got pretty good at finding uses of closed-over variables
>> modified in a loop, but the workarounds were not ideal.
>>
>> var i;
>> for (i = 0; i < arr.length; ++i) {
>>   f(function (i) { return function () { /* Do something with */ arr[i]; }
>> }(i));
>> }
>>
>> Block scoping is just better for code that uses loops, variables, and
>> function expressions.
>>
>>
>> _______________________________________________
>> 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: Proposal: if variable initialization

Isiah Meadows-2
In reply to this post by kai zhu
Fun fact: you'd be surprised how many non-trivial JS stuff there is.
If you've ever used jQuery selectors, you've used a selector engine
implemented in JS [1], which uses quite a few advanced data structure
and algorithm techniques. Not all JavaScript is inherently async, nor
does it need to be. Updating the UI in larger web apps can't be easily
done synchronously, and it requires significant familiarity with data
structures. The alternative is to do it all server side, but then
you're wasting resources doing what your client could do just as
easily - it doesn't necessarily have all the data, but it certainly
has a working CPU and RAM chip. At smaller scale like with typical
business websites, it doesn't matter, but at even mid-level startup
scale, it drives server costs down quite a bit. (If you can move 15%
of the RAM/CPU workload to the client without affecting perceptible
performance, that's 15% fewer servers/data clusters you need. For
Facebook and Google, that could mean one less data center they have to
build and maintain.)

Also, little language annoyances are themselves worth tackling as real
problems. Programming languages aren't just made to solve problems.
They are also themselves an art form unto themselves.

[1]: https://github.com/jquery/sizzle/blob/master/src/sizzle.js
-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Wed, Mar 21, 2018 at 3:56 PM, kai zhu <[hidden email]> wrote:

> @mike yes that’s true, but issues with blocking-code javascript
> data-structures/algorithms are rarely the reason web-projects fail.  they
> fail largely due to unresolvable integration-level io/workflow issues (that
> are unique only to javascript).  block-scoping fixes the insignificant
> former, while exacerbating the more pressing latter, by encouraging people
> to pollute variable-declarations all-over-the-place; making it harder to
> discern-and-debug which ones are critical io-related closure-variables and
> which ones are not.
>
> data-structure and algorithmic coding-skills are rarely all that useful in
> javascript (just throw sqlite3 at it and it will likely go away).
> integration-level debugging-skills (and knowledge of which coding
> design-patterns to employ to make io easier to debug) are far more valuable
> and correlable to successfully shipping a web-project.
>
> On Mar 22, 2018, at 3:47 AM, Mike Samuel <[hidden email]> wrote:
>
>
>
> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <[hidden email]>
> wrote:
>>
>> Because block-level scoping is a very good way to avoid certain bugs and
>> is easier to reason about. Especially when considering project successors.
>
>
> +1.  function-scoped variables in loop bodies caused tons of bugs before
> let-scoped variables and were a main motivating case.
>
> var i;
> for (i = 0; i < arr.length; ++i) {
>   f(function () { /* Do something with */ arr[i]; });
> }
>
> vs
>
> for (let i = 0; i < arr.length; ++i) {
>   f(function () { /* Do something with */ arr[i]; });
> }
>
> Yes, linters got pretty good at finding uses of closed-over variables
> modified in a loop, but the workarounds were not ideal.
>
> var i;
> for (i = 0; i < arr.length; ++i) {
>   f(function (i) { return function () { /* Do something with */ arr[i]; }
> }(i));
> }
>
> Block scoping is just better for code that uses loops, variables, and
> function expressions.
>
>
>
> _______________________________________________
> 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: Proposal: if variable initialization

Rodrigo
In reply to this post by Mike Samuel
Not just let-scopes, but the introduction of `async/await` also
welcomes the introduction of if-scoped variables.

    if (const data = await collection.find({}).toArray(); data.length > 10) {
        console.log(data);
    } else if (data.length > 0) {
        console.log(data);
    } else {
        console.log(data);
    }

And, as mentioned by @jerry, this can be extended to `switch` and
`while`. Golang has `switch(;)` initialization too afaik.

    switch( const today = new Date(); today.getDay() ) {
         case 0:
            console.log( "Don't work on %s", today.toString() );
            break;
    }

`while` would be a bit unnecessary, due to the fact that it can be
replicated with `for( <assign>; <expression>; )`, but could be
available for consistency with `if` and `switch`.

El mié., 21 mar. 2018 19:47, Mike Samuel <[hidden email]> escribió:


On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <[hidden email]> wrote:
Because block-level scoping is a very good way to avoid certain bugs and is easier to reason about. Especially when considering project successors. 

+1.  function-scoped variables in loop bodies caused tons of bugs before let-scoped variables and were a main motivating case.

var i;
for (i = 0; i < arr.length; ++i) {
  f(function () { /* Do something with */ arr[i]; });
}

vs

for (let i = 0; i < arr.length; ++i) {
  f(function () { /* Do something with */ arr[i]; });
}

Yes, linters got pretty good at finding uses of closed-over variables modified in a loop, but the workarounds were not ideal.

var i;
for (i = 0; i < arr.length; ++i) {
  f(function (i) { return function () { /* Do something with */ arr[i]; } }(i));
}

Block scoping is just better for code that uses loops, variables, and function expressions.

_______________________________________________
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: Proposal: if variable initialization

Isiah Meadows-2
<concern>
I get the nagging feeling someone is eventually going to complain that
this feature is unnecessary and smells too much like `let` blocks:

- Relevant thread: https://esdiscuss.org/topic/revive-let-blocks
- How it ended:
https://esdiscuss.org/topic/the-tragedy-of-the-common-lisp-or-why-large-languages-explode-was-revive-let-blocks
</concern>

It seems odd to extend it to `switch`, especially with an added
condition like that. It seems odd to do something that's already
easily accomplished with just an extra newline, with hardly any more
typing:

```js
const today = new Date()
switch (today.getDay()) {
    // ...
}
```

(The `if` examples don't have this same issue, BTW.)

One statement I'd *like* to see this extended to is `while`, but it's
partially duplicative of the C-style `for` (so it kind of feels wrong
to add in a way). Also, it doesn't make sense to add for `do { ... }
while (...)`, since the condition is after the block. So it seems this
only really makes sense for `if`.

I do have one other related thing I'd like to see: add a `let foo =
expr() else { ... }` variant, with a line terminator restriction
before the `else` so it can't be confused with an `else` within an
`if`.


-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <[hidden email]> wrote:

> Not just let-scopes, but the introduction of `async/await` also
> welcomes the introduction of if-scoped variables.
>
>     if (const data = await collection.find({}).toArray(); data.length > 10)
> {
>         console.log(data);
>     } else if (data.length > 0) {
>         console.log(data);
>     } else {
>         console.log(data);
>     }
>
> And, as mentioned by @jerry, this can be extended to `switch` and
> `while`. Golang has `switch(;)` initialization too afaik.
>
>     switch( const today = new Date(); today.getDay() ) {
>          case 0:
>             console.log( "Don't work on %s", today.toString() );
>             break;
>     }
>
> `while` would be a bit unnecessary, due to the fact that it can be
> replicated with `for( <assign>; <expression>; )`, but could be
> available for consistency with `if` and `switch`.
>
> El mié., 21 mar. 2018 19:47, Mike Samuel <[hidden email]> escribió:
>>
>>
>>
>> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <[hidden email]>
>> wrote:
>>>
>>> Because block-level scoping is a very good way to avoid certain bugs and
>>> is easier to reason about. Especially when considering project successors.
>>
>>
>> +1.  function-scoped variables in loop bodies caused tons of bugs before
>> let-scoped variables and were a main motivating case.
>>
>> var i;
>> for (i = 0; i < arr.length; ++i) {
>>   f(function () { /* Do something with */ arr[i]; });
>> }
>>
>> vs
>>
>> for (let i = 0; i < arr.length; ++i) {
>>   f(function () { /* Do something with */ arr[i]; });
>> }
>>
>> Yes, linters got pretty good at finding uses of closed-over variables
>> modified in a loop, but the workarounds were not ideal.
>>
>> var i;
>> for (i = 0; i < arr.length; ++i) {
>>   f(function (i) { return function () { /* Do something with */ arr[i]; }
>> }(i));
>> }
>>
>> Block scoping is just better for code that uses loops, variables, and
>> function expressions.
>>
>> _______________________________________________
>> 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
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: if variable initialization

Rodrigo
I agree, the `switch` statement was not on my radar and I don't see
that need, it's the scoped `if` constructs that would make code
cleaner.

On Thu, Mar 22, 2018 at 8:50 AM, Isiah Meadows <[hidden email]> wrote:

> <concern>
> I get the nagging feeling someone is eventually going to complain that
> this feature is unnecessary and smells too much like `let` blocks:
>
> - Relevant thread: https://esdiscuss.org/topic/revive-let-blocks
> - How it ended:
> https://esdiscuss.org/topic/the-tragedy-of-the-common-lisp-or-why-large-languages-explode-was-revive-let-blocks
> </concern>
>
> It seems odd to extend it to `switch`, especially with an added
> condition like that. It seems odd to do something that's already
> easily accomplished with just an extra newline, with hardly any more
> typing:
>
> ```js
> const today = new Date()
> switch (today.getDay()) {
>     // ...
> }
> ```
>
> (The `if` examples don't have this same issue, BTW.)
>
> One statement I'd *like* to see this extended to is `while`, but it's
> partially duplicative of the C-style `for` (so it kind of feels wrong
> to add in a way). Also, it doesn't make sense to add for `do { ... }
> while (...)`, since the condition is after the block. So it seems this
> only really makes sense for `if`.
>
> I do have one other related thing I'd like to see: add a `let foo =
> expr() else { ... }` variant, with a line terminator restriction
> before the `else` so it can't be confused with an `else` within an
> `if`.
>
>
> -----
>
> Isiah Meadows
> [hidden email]
>
> Looking for web consulting? Or a new website?
> Send me an email and we can get started.
> www.isiahmeadows.com
>
>
> On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <[hidden email]> wrote:
>> Not just let-scopes, but the introduction of `async/await` also
>> welcomes the introduction of if-scoped variables.
>>
>>     if (const data = await collection.find({}).toArray(); data.length > 10)
>> {
>>         console.log(data);
>>     } else if (data.length > 0) {
>>         console.log(data);
>>     } else {
>>         console.log(data);
>>     }
>>
>> And, as mentioned by @jerry, this can be extended to `switch` and
>> `while`. Golang has `switch(;)` initialization too afaik.
>>
>>     switch( const today = new Date(); today.getDay() ) {
>>          case 0:
>>             console.log( "Don't work on %s", today.toString() );
>>             break;
>>     }
>>
>> `while` would be a bit unnecessary, due to the fact that it can be
>> replicated with `for( <assign>; <expression>; )`, but could be
>> available for consistency with `if` and `switch`.
>>
>> El mié., 21 mar. 2018 19:47, Mike Samuel <[hidden email]> escribió:
>>>
>>>
>>>
>>> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <[hidden email]>
>>> wrote:
>>>>
>>>> Because block-level scoping is a very good way to avoid certain bugs and
>>>> is easier to reason about. Especially when considering project successors.
>>>
>>>
>>> +1.  function-scoped variables in loop bodies caused tons of bugs before
>>> let-scoped variables and were a main motivating case.
>>>
>>> var i;
>>> for (i = 0; i < arr.length; ++i) {
>>>   f(function () { /* Do something with */ arr[i]; });
>>> }
>>>
>>> vs
>>>
>>> for (let i = 0; i < arr.length; ++i) {
>>>   f(function () { /* Do something with */ arr[i]; });
>>> }
>>>
>>> Yes, linters got pretty good at finding uses of closed-over variables
>>> modified in a loop, but the workarounds were not ideal.
>>>
>>> var i;
>>> for (i = 0; i < arr.length; ++i) {
>>>   f(function (i) { return function () { /* Do something with */ arr[i]; }
>>> }(i));
>>> }
>>>
>>> Block scoping is just better for code that uses loops, variables, and
>>> function expressions.
>>>
>>> _______________________________________________
>>> 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
>>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: if variable initialization

Mike Samuel
In reply to this post by Isiah Meadows-2


On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <[hidden email]> wrote:

I do have one other related thing I'd like to see: add a `let foo =
expr() else { ... }` variant, with a line terminator restriction
before the `else` so it can't be confused with an `else` within an
`if`.

Making it a restricted production would solve the grammatical ambiguity
for existing code, but maybe in an errorprone way for future code:

    if (c) let foo = expr() else { ... } // else attaches to let
    if (c) let foo = expr(); else { ... } // else attaches to if


Would the semantics differ from

   let foo = expr() || ({} => { ... })()

?



 

-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <[hidden email]> wrote:
> Not just let-scopes, but the introduction of `async/await` also
> welcomes the introduction of if-scoped variables.
>
>     if (const data = await collection.find({}).toArray(); data.length > 10)
> {
>         console.log(data);
>     } else if (data.length > 0) {
>         console.log(data);
>     } else {
>         console.log(data);
>     }
>
> And, as mentioned by @jerry, this can be extended to `switch` and
> `while`. Golang has `switch(;)` initialization too afaik.
>
>     switch( const today = new Date(); today.getDay() ) {
>          case 0:
>             console.log( "Don't work on %s", today.toString() );
>             break;
>     }
>
> `while` would be a bit unnecessary, due to the fact that it can be
> replicated with `for( <assign>; <expression>; )`, but could be
> available for consistency with `if` and `switch`.
>
> El mié., 21 mar. 2018 19:47, Mike Samuel <[hidden email]> escribió:
>>
>>
>>
>> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <[hidden email]>
>> wrote:
>>>
>>> Because block-level scoping is a very good way to avoid certain bugs and
>>> is easier to reason about. Especially when considering project successors.
>>
>>
>> +1.  function-scoped variables in loop bodies caused tons of bugs before
>> let-scoped variables and were a main motivating case.
>>
>> var i;
>> for (i = 0; i < arr.length; ++i) {
>>   f(function () { /* Do something with */ arr[i]; });
>> }
>>
>> vs
>>
>> for (let i = 0; i < arr.length; ++i) {
>>   f(function () { /* Do something with */ arr[i]; });
>> }
>>
>> Yes, linters got pretty good at finding uses of closed-over variables
>> modified in a loop, but the workarounds were not ideal.
>>
>> var i;
>> for (i = 0; i < arr.length; ++i) {
>>   f(function (i) { return function () { /* Do something with */ arr[i]; }
>> }(i));
>> }
>>
>> Block scoping is just better for code that uses loops, variables, and
>> function expressions.
>>
>> _______________________________________________
>> 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
>


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

Re: Proposal: if variable initialization

Michael Luder-Rosefield
That strikes me as territory the 'do expression' proposal https://github.com/tc39/proposal-do-expressions is more fitted for:

    const x = do { if (c) expr; else { ... } };

What I'd like for this proposal is something that works consistently and obviously for all blocks with a parenthesised element to them. When they're formally separated by semi-colons, as in `for (a;b;c)`, each of `a,b,c` acts as an expression. Why not allow any of those expressions to be replaced by a statement block that acts like a do expression, each of which's scope is nested under the previous one and are available to the following block?

That didn't come out very clearly, so let's try with an example:

  for ({ 
      let x = 1, y = 2; 
      console.log("I'll be printed every loop!");
    }; {
      let s = 'some string';
      if (y%7 === 0) x === y;
      else x < 1000;
    }; {
      let s = 'some other string';
      x+=1;
      if (y%3 === 0) y += 2;
      else y += 1;
    }) {
      // whatever code here
      // local scope hierarchy is 
      //   { 
      //     x, 
      //    y, 
      //    __SCOPE__: { 
      //      s: 'some string', 
      //      __SCOPE__: { 
      //        s: 'some other string' 
      //      } 
      //    } 
      //  }
    }

I'm just using some random logic in the blocks to illustrate the point: all the variables declared in the blocks are accessible in the for block, but the 'some string' `s` is masked by the 'some other string' `s` in the child scope. The termination condition in the second block can vary each loop, as can the iteration operation in the last block, and is simply the last value in the block as-per do expressions.

On Thu, 22 Mar 2018 at 15:44 Mike Samuel <[hidden email]> wrote:
On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <[hidden email]> wrote:

I do have one other related thing I'd like to see: add a `let foo =
expr() else { ... }` variant, with a line terminator restriction
before the `else` so it can't be confused with an `else` within an
`if`.

Making it a restricted production would solve the grammatical ambiguity
for existing code, but maybe in an errorprone way for future code:

    if (c) let foo = expr() else { ... } // else attaches to let
    if (c) let foo = expr(); else { ... } // else attaches to if


Would the semantics differ from

   let foo = expr() || ({} => { ... })()

?



 

-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <[hidden email]> wrote:
> Not just let-scopes, but the introduction of `async/await` also
> welcomes the introduction of if-scoped variables.
>
>     if (const data = await collection.find({}).toArray(); data.length > 10)
> {
>         console.log(data);
>     } else if (data.length > 0) {
>         console.log(data);
>     } else {
>         console.log(data);
>     }
>
> And, as mentioned by @jerry, this can be extended to `switch` and
> `while`. Golang has `switch(;)` initialization too afaik.
>
>     switch( const today = new Date(); today.getDay() ) {
>          case 0:
>             console.log( "Don't work on %s", today.toString() );
>             break;
>     }
>
> `while` would be a bit unnecessary, due to the fact that it can be
> replicated with `for( <assign>; <expression>; )`, but could be
> available for consistency with `if` and `switch`.
>
> El mié., 21 mar. 2018 19:47, Mike Samuel <[hidden email]> escribió:
>>
>>
>>
>> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <[hidden email]>
>> wrote:
>>>
>>> Because block-level scoping is a very good way to avoid certain bugs and
>>> is easier to reason about. Especially when considering project successors.
>>
>>
>> +1.  function-scoped variables in loop bodies caused tons of bugs before
>> let-scoped variables and were a main motivating case.
>>
>> var i;
>> for (i = 0; i < arr.length; ++i) {
>>   f(function () { /* Do something with */ arr[i]; });
>> }
>>
>> vs
>>
>> for (let i = 0; i < arr.length; ++i) {
>>   f(function () { /* Do something with */ arr[i]; });
>> }
>>
>> Yes, linters got pretty good at finding uses of closed-over variables
>> modified in a loop, but the workarounds were not ideal.
>>
>> var i;
>> for (i = 0; i < arr.length; ++i) {
>>   f(function (i) { return function () { /* Do something with */ arr[i]; }
>> }(i));
>> }
>>
>> Block scoping is just better for code that uses loops, variables, and
>> function expressions.
>>
>> _______________________________________________
>> 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
>
_______________________________________________
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: Proposal: if variable initialization

Isiah Meadows-2
Probably true, more so than the `if (var ...)`/etc. (which can't be as
easily desugared). My `else` variant desugars more to something that
is also easily simulated, and it's a less common case:

```js
let foo = bar else return baz;

// Desugared
let _tmp = bar;
if (tmp == null) return baz;
let foo = _tmp;
```

In this case, there's also the question of whether to require a
`return` in all code paths, which probably makes this a bit more
complicated than what would be worth for such a simple language
feature.
-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Thu, Mar 22, 2018 at 12:23 PM, Michael Luder-Rosefield
<[hidden email]> wrote:

> That strikes me as territory the 'do expression' proposal
> https://github.com/tc39/proposal-do-expressions is more fitted for:
>
>     const x = do { if (c) expr; else { ... } };
>
> What I'd like for this proposal is something that works consistently and
> obviously for all blocks with a parenthesised element to them. When they're
> formally separated by semi-colons, as in `for (a;b;c)`, each of `a,b,c` acts
> as an expression. Why not allow any of those expressions to be replaced by a
> statement block that acts like a do expression, each of which's scope is
> nested under the previous one and are available to the following block?
>
> That didn't come out very clearly, so let's try with an example:
>
>   for ({
>       let x = 1, y = 2;
>       console.log("I'll be printed every loop!");
>     }; {
>       let s = 'some string';
>       if (y%7 === 0) x === y;
>       else x < 1000;
>     }; {
>       let s = 'some other string';
>       x+=1;
>       if (y%3 === 0) y += 2;
>       else y += 1;
>     }) {
>       // whatever code here
>       // local scope hierarchy is
>       //   {
>       //     x,
>       //    y,
>       //    __SCOPE__: {
>       //      s: 'some string',
>       //      __SCOPE__: {
>       //        s: 'some other string'
>       //      }
>       //    }
>       //  }
>     }
>
> I'm just using some random logic in the blocks to illustrate the point: all
> the variables declared in the blocks are accessible in the for block, but
> the 'some string' `s` is masked by the 'some other string' `s` in the child
> scope. The termination condition in the second block can vary each loop, as
> can the iteration operation in the last block, and is simply the last value
> in the block as-per do expressions.
>
> On Thu, 22 Mar 2018 at 15:44 Mike Samuel <[hidden email]> wrote:
>>
>> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <[hidden email]>
>> wrote:
>>>
>>>
>>> I do have one other related thing I'd like to see: add a `let foo =
>>> expr() else { ... }` variant, with a line terminator restriction
>>> before the `else` so it can't be confused with an `else` within an
>>> `if`.
>>
>>
>> Making it a restricted production would solve the grammatical ambiguity
>> for existing code, but maybe in an errorprone way for future code:
>>
>>     if (c) let foo = expr() else { ... } // else attaches to let
>>     if (c) let foo = expr(); else { ... } // else attaches to if
>>
>>
>> Would the semantics differ from
>>
>>    let foo = expr() || ({} => { ... })()
>>
>> ?
>>
>>
>>
>>
>>>
>>>
>>> -----
>>>
>>> Isiah Meadows
>>> [hidden email]
>>>
>>> Looking for web consulting? Or a new website?
>>> Send me an email and we can get started.
>>> www.isiahmeadows.com
>>>
>>>
>>> On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <[hidden email]> wrote:
>>> > Not just let-scopes, but the introduction of `async/await` also
>>> > welcomes the introduction of if-scoped variables.
>>> >
>>> >     if (const data = await collection.find({}).toArray(); data.length >
>>> > 10)
>>> > {
>>> >         console.log(data);
>>> >     } else if (data.length > 0) {
>>> >         console.log(data);
>>> >     } else {
>>> >         console.log(data);
>>> >     }
>>> >
>>> > And, as mentioned by @jerry, this can be extended to `switch` and
>>> > `while`. Golang has `switch(;)` initialization too afaik.
>>> >
>>> >     switch( const today = new Date(); today.getDay() ) {
>>> >          case 0:
>>> >             console.log( "Don't work on %s", today.toString() );
>>> >             break;
>>> >     }
>>> >
>>> > `while` would be a bit unnecessary, due to the fact that it can be
>>> > replicated with `for( <assign>; <expression>; )`, but could be
>>> > available for consistency with `if` and `switch`.
>>> >
>>> > El mié., 21 mar. 2018 19:47, Mike Samuel <[hidden email]>
>>> > escribió:
>>> >>
>>> >>
>>> >>
>>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton
>>> >> <[hidden email]>
>>> >> wrote:
>>> >>>
>>> >>> Because block-level scoping is a very good way to avoid certain bugs
>>> >>> and
>>> >>> is easier to reason about. Especially when considering project
>>> >>> successors.
>>> >>
>>> >>
>>> >> +1.  function-scoped variables in loop bodies caused tons of bugs
>>> >> before
>>> >> let-scoped variables and were a main motivating case.
>>> >>
>>> >> var i;
>>> >> for (i = 0; i < arr.length; ++i) {
>>> >>   f(function () { /* Do something with */ arr[i]; });
>>> >> }
>>> >>
>>> >> vs
>>> >>
>>> >> for (let i = 0; i < arr.length; ++i) {
>>> >>   f(function () { /* Do something with */ arr[i]; });
>>> >> }
>>> >>
>>> >> Yes, linters got pretty good at finding uses of closed-over variables
>>> >> modified in a loop, but the workarounds were not ideal.
>>> >>
>>> >> var i;
>>> >> for (i = 0; i < arr.length; ++i) {
>>> >>   f(function (i) { return function () { /* Do something with */
>>> >> arr[i]; }
>>> >> }(i));
>>> >> }
>>> >>
>>> >> Block scoping is just better for code that uses loops, variables, and
>>> >> function expressions.
>>> >>
>>> >> _______________________________________________
>>> >> 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
>>> >
>>
>> _______________________________________________
>> 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: Proposal: if variable initialization

Naveen Chawla
I'm still not seeing a compelling case for not allowing `const` / `let` declarations to be evaluated as expressions. Or I've missed it.

As was noted,

`if(x = 5)` is already allowed.

Is `if(const x = 5)` really that much of a stretch?

To answer a concern about a function call like `myFunction(const x = 7)`, of course the scope of `x` would be where it is declared. It can't be anywhere else (like inside myFunction or something).

On Thu, 22 Mar 2018 at 22:53 Isiah Meadows <[hidden email]> wrote:
Probably true, more so than the `if (var ...)`/etc. (which can't be as
easily desugared). My `else` variant desugars more to something that
is also easily simulated, and it's a less common case:

```js
let foo = bar else return baz;

// Desugared
let _tmp = bar;
if (tmp == null) return baz;
let foo = _tmp;
```

In this case, there's also the question of whether to require a
`return` in all code paths, which probably makes this a bit more
complicated than what would be worth for such a simple language
feature.
-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Thu, Mar 22, 2018 at 12:23 PM, Michael Luder-Rosefield
<[hidden email]> wrote:
> That strikes me as territory the 'do expression' proposal
> https://github.com/tc39/proposal-do-expressions is more fitted for:
>
>     const x = do { if (c) expr; else { ... } };
>
> What I'd like for this proposal is something that works consistently and
> obviously for all blocks with a parenthesised element to them. When they're
> formally separated by semi-colons, as in `for (a;b;c)`, each of `a,b,c` acts
> as an expression. Why not allow any of those expressions to be replaced by a
> statement block that acts like a do expression, each of which's scope is
> nested under the previous one and are available to the following block?
>
> That didn't come out very clearly, so let's try with an example:
>
>   for ({
>       let x = 1, y = 2;
>       console.log("I'll be printed every loop!");
>     }; {
>       let s = 'some string';
>       if (y%7 === 0) x === y;
>       else x < 1000;
>     }; {
>       let s = 'some other string';
>       x+=1;
>       if (y%3 === 0) y += 2;
>       else y += 1;
>     }) {
>       // whatever code here
>       // local scope hierarchy is
>       //   {
>       //     x,
>       //    y,
>       //    __SCOPE__: {
>       //      s: 'some string',
>       //      __SCOPE__: {
>       //        s: 'some other string'
>       //      }
>       //    }
>       //  }
>     }
>
> I'm just using some random logic in the blocks to illustrate the point: all
> the variables declared in the blocks are accessible in the for block, but
> the 'some string' `s` is masked by the 'some other string' `s` in the child
> scope. The termination condition in the second block can vary each loop, as
> can the iteration operation in the last block, and is simply the last value
> in the block as-per do expressions.
>
> On Thu, 22 Mar 2018 at 15:44 Mike Samuel <[hidden email]> wrote:
>>
>> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <[hidden email]>
>> wrote:
>>>
>>>
>>> I do have one other related thing I'd like to see: add a `let foo =
>>> expr() else { ... }` variant, with a line terminator restriction
>>> before the `else` so it can't be confused with an `else` within an
>>> `if`.
>>
>>
>> Making it a restricted production would solve the grammatical ambiguity
>> for existing code, but maybe in an errorprone way for future code:
>>
>>     if (c) let foo = expr() else { ... } // else attaches to let
>>     if (c) let foo = expr(); else { ... } // else attaches to if
>>
>>
>> Would the semantics differ from
>>
>>    let foo = expr() || ({} => { ... })()
>>
>> ?
>>
>>
>>
>>
>>>
>>>
>>> -----
>>>
>>> Isiah Meadows
>>> [hidden email]
>>>
>>> Looking for web consulting? Or a new website?
>>> Send me an email and we can get started.
>>> www.isiahmeadows.com
>>>
>>>
>>> On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <[hidden email]> wrote:
>>> > Not just let-scopes, but the introduction of `async/await` also
>>> > welcomes the introduction of if-scoped variables.
>>> >
>>> >     if (const data = await collection.find({}).toArray(); data.length >
>>> > 10)
>>> > {
>>> >         console.log(data);
>>> >     } else if (data.length > 0) {
>>> >         console.log(data);
>>> >     } else {
>>> >         console.log(data);
>>> >     }
>>> >
>>> > And, as mentioned by @jerry, this can be extended to `switch` and
>>> > `while`. Golang has `switch(;)` initialization too afaik.
>>> >
>>> >     switch( const today = new Date(); today.getDay() ) {
>>> >          case 0:
>>> >             console.log( "Don't work on %s", today.toString() );
>>> >             break;
>>> >     }
>>> >
>>> > `while` would be a bit unnecessary, due to the fact that it can be
>>> > replicated with `for( <assign>; <expression>; )`, but could be
>>> > available for consistency with `if` and `switch`.
>>> >
>>> > El mié., 21 mar. 2018 19:47, Mike Samuel <[hidden email]>
>>> > escribió:
>>> >>
>>> >>
>>> >>
>>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton
>>> >> <[hidden email]>
>>> >> wrote:
>>> >>>
>>> >>> Because block-level scoping is a very good way to avoid certain bugs
>>> >>> and
>>> >>> is easier to reason about. Especially when considering project
>>> >>> successors.
>>> >>
>>> >>
>>> >> +1.  function-scoped variables in loop bodies caused tons of bugs
>>> >> before
>>> >> let-scoped variables and were a main motivating case.
>>> >>
>>> >> var i;
>>> >> for (i = 0; i < arr.length; ++i) {
>>> >>   f(function () { /* Do something with */ arr[i]; });
>>> >> }
>>> >>
>>> >> vs
>>> >>
>>> >> for (let i = 0; i < arr.length; ++i) {
>>> >>   f(function () { /* Do something with */ arr[i]; });
>>> >> }
>>> >>
>>> >> Yes, linters got pretty good at finding uses of closed-over variables
>>> >> modified in a loop, but the workarounds were not ideal.
>>> >>
>>> >> var i;
>>> >> for (i = 0; i < arr.length; ++i) {
>>> >>   f(function (i) { return function () { /* Do something with */
>>> >> arr[i]; }
>>> >> }(i));
>>> >> }
>>> >>
>>> >> Block scoping is just better for code that uses loops, variables, and
>>> >> function expressions.
>>> >>
>>> >> _______________________________________________
>>> >> 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
>>> >
>>
>> _______________________________________________
>> 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

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

Re: Proposal: if variable initialization

kai zhu
unlike all other popular c-derivatives, javascript is the only one that's *not* a blocking-code language by design.  maybe tc39 should do some outreach to educate the many language-designers and polyglots who only know blocking-code patterns of this simple fact.

as i've said before, adding these foreign, blocking-code design-patterns from java/c#/python/c++ can only get you so far with insignificant, low-level library-code, which is not what javascript is about.  javascript is about integrating non-blocking io and workflows, so that browser/webview UX’s don’t block-and-freeze and give the appearance a webapp has crashed.

but async/await will save us! …no it will not.  the hard-part of integration-level javascript is not writing non-blocking code, but debugging non-blocking code.  and debugging non-blocking generator-magic (and promise-magic), is generally more difficult than debugging magic-less recursive-callbacks.

there is currently an industry-glut of so-called “senior” javascript-developers, who only know how to write low-level library-code (and bikeshed them to death with let, const, destructuring, etc...), but are clueless on how to integrate whatever-it-is-they-wrote into a shippable web-product.  no, they usually need an “intermediate” frontend-developer to do that (who oftentimes didn’t have formal cs-training and wasn't brainwashed with all that blocking-code cr*p that hinders the "senior” developer from carrying out integration-work).

-kai

On Mar 23, 2018, at 3:21 PM, Naveen Chawla <[hidden email]> wrote:

I'm still not seeing a compelling case for not allowing `const` / `let` declarations to be evaluated as expressions. Or I've missed it.

As was noted,

`if(x = 5)` is already allowed.

Is `if(const x = 5)` really that much of a stretch?

To answer a concern about a function call like `myFunction(const x = 7)`, of course the scope of `x` would be where it is declared. It can't be anywhere else (like inside myFunction or something).

On Thu, 22 Mar 2018 at 22:53 Isiah Meadows <[hidden email]> wrote:
Probably true, more so than the `if (var ...)`/etc. (which can't be as
easily desugared). My `else` variant desugars more to something that
is also easily simulated, and it's a less common case:

```js
let foo = bar else return baz;

// Desugared
let _tmp = bar;
if (tmp == null) return baz;
let foo = _tmp;
```

In this case, there's also the question of whether to require a
`return` in all code paths, which probably makes this a bit more
complicated than what would be worth for such a simple language
feature.
-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Thu, Mar 22, 2018 at 12:23 PM, Michael Luder-Rosefield
<[hidden email]> wrote:
> That strikes me as territory the 'do expression' proposal
> https://github.com/tc39/proposal-do-expressions is more fitted for:
>
>     const x = do { if (c) expr; else { ... } };
>
> What I'd like for this proposal is something that works consistently and
> obviously for all blocks with a parenthesised element to them. When they're
> formally separated by semi-colons, as in `for (a;b;c)`, each of `a,b,c` acts
> as an expression. Why not allow any of those expressions to be replaced by a
> statement block that acts like a do expression, each of which's scope is
> nested under the previous one and are available to the following block?
>
> That didn't come out very clearly, so let's try with an example:
>
>   for ({
>       let x = 1, y = 2;
>       console.log("I'll be printed every loop!");
>     }; {
>       let s = 'some string';
>       if (y%7 === 0) x === y;
>       else x < 1000;
>     }; {
>       let s = 'some other string';
>       x+=1;
>       if (y%3 === 0) y += 2;
>       else y += 1;
>     }) {
>       // whatever code here
>       // local scope hierarchy is
>       //   {
>       //     x,
>       //    y,
>       //    __SCOPE__: {
>       //      s: 'some string',
>       //      __SCOPE__: {
>       //        s: 'some other string'
>       //      }
>       //    }
>       //  }
>     }
>
> I'm just using some random logic in the blocks to illustrate the point: all
> the variables declared in the blocks are accessible in the for block, but
> the 'some string' `s` is masked by the 'some other string' `s` in the child
> scope. The termination condition in the second block can vary each loop, as
> can the iteration operation in the last block, and is simply the last value
> in the block as-per do expressions.
>
> On Thu, 22 Mar 2018 at 15:44 Mike Samuel <[hidden email]> wrote:
>>
>> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <[hidden email]>
>> wrote:
>>>
>>>
>>> I do have one other related thing I'd like to see: add a `let foo =
>>> expr() else { ... }` variant, with a line terminator restriction
>>> before the `else` so it can't be confused with an `else` within an
>>> `if`.
>>
>>
>> Making it a restricted production would solve the grammatical ambiguity
>> for existing code, but maybe in an errorprone way for future code:
>>
>>     if (c) let foo = expr() else { ... } // else attaches to let
>>     if (c) let foo = expr(); else { ... } // else attaches to if
>>
>>
>> Would the semantics differ from
>>
>>    let foo = expr() || ({} => { ... })()
>>
>> ?
>>
>>
>>
>>
>>>
>>>
>>> -----
>>>
>>> Isiah Meadows
>>> [hidden email]
>>>
>>> Looking for web consulting? Or a new website?
>>> Send me an email and we can get started.
>>> www.isiahmeadows.com
>>>
>>>
>>> On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <[hidden email]> wrote:
>>> > Not just let-scopes, but the introduction of `async/await` also
>>> > welcomes the introduction of if-scoped variables.
>>> >
>>> >     if (const data = await collection.find({}).toArray(); data.length >
>>> > 10)
>>> > {
>>> >         console.log(data);
>>> >     } else if (data.length > 0) {
>>> >         console.log(data);
>>> >     } else {
>>> >         console.log(data);
>>> >     }
>>> >
>>> > And, as mentioned by @jerry, this can be extended to `switch` and
>>> > `while`. Golang has `switch(;)` initialization too afaik.
>>> >
>>> >     switch( const today = new Date(); today.getDay() ) {
>>> >          case 0:
>>> >             console.log( "Don't work on %s", today.toString() );
>>> >             break;
>>> >     }
>>> >
>>> > `while` would be a bit unnecessary, due to the fact that it can be
>>> > replicated with `for( <assign>; <expression>; )`, but could be
>>> > available for consistency with `if` and `switch`.
>>> >
>>> > El mié., 21 mar. 2018 19:47, Mike Samuel <[hidden email]>
>>> > escribió:
>>> >>
>>> >>
>>> >>
>>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton
>>> >> <[hidden email]>
>>> >> wrote:
>>> >>>
>>> >>> Because block-level scoping is a very good way to avoid certain bugs
>>> >>> and
>>> >>> is easier to reason about. Especially when considering project
>>> >>> successors.
>>> >>
>>> >>
>>> >> +1.  function-scoped variables in loop bodies caused tons of bugs
>>> >> before
>>> >> let-scoped variables and were a main motivating case.
>>> >>
>>> >> var i;
>>> >> for (i = 0; i < arr.length; ++i) {
>>> >>   f(function () { /* Do something with */ arr[i]; });
>>> >> }
>>> >>
>>> >> vs
>>> >>
>>> >> for (let i = 0; i < arr.length; ++i) {
>>> >>   f(function () { /* Do something with */ arr[i]; });
>>> >> }
>>> >>
>>> >> Yes, linters got pretty good at finding uses of closed-over variables
>>> >> modified in a loop, but the workarounds were not ideal.
>>> >>
>>> >> var i;
>>> >> for (i = 0; i < arr.length; ++i) {
>>> >>   f(function (i) { return function () { /* Do something with */
>>> >> arr[i]; }
>>> >> }(i));
>>> >> }
>>> >>
>>> >> Block scoping is just better for code that uses loops, variables, and
>>> >> function expressions.
>>> >>
>>> >> _______________________________________________
>>> >> 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
>>> >
>>
>> _______________________________________________
>> 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
_______________________________________________
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: Proposal: if variable initialization

Rodrigo
In reply to this post by Naveen Chawla
@Naveen, I think it's best to avoid this road altogether and keep
initialization clean, even though assignment isn't.

The proposal is that given `for(;;)` hence `if(;)` instead of given
`x=y` hence `let x=y`.

But yes, `if( x = 5)` is already allowed, but it's confusing and hard to read.

Confusing on what is being compared on multiple statements: `if((const
x = 5, y = 10) > 0)`

Confusing when destructuring, on what's being compared: `if(let [x,y] = [1,2])`

Confusing when multiple statements: `if ((x = 10, y = 20) > 15)`

Looks like an error: `if( x = 5 )` versus `if( x == 5)`, did the
programmer forget the `=`?

And if you introduce nesting initializations everywhere outside the
`if`, that's basically an invitation for readability nightmare. `let`
and `const` anywhere introduce 2 conflicting best-practices:

- Rule 1: declare your variables that are used exclusively within `if`
blocks within the `if` parens

- Rule 2: don't declare variables within another statement (so that
people will refrain from doing `foo( let x=10 )`

Consider that, historically, other languages such as Perl allowed `if(
(my $x = 1) > 0)` and `foo( my $x = 100)` and became the ugly child of
power programming; whereas Golang, born much later, has limited
initializations to things such as `if( x:=1; x > 0)` and has kept
things quite minimalistic (and clear for the programmer).

```perl
# realworld example, hard to find variable declaration:

$redis->subscribe( 'queue', my $callback = sub {
    ...
});
```


On Fri, Mar 23, 2018 at 7:21 AM, Naveen Chawla <[hidden email]> wrote:

> I'm still not seeing a compelling case for not allowing `const` / `let`
> declarations to be evaluated as expressions. Or I've missed it.
>
> As was noted,
>
> `if(x = 5)` is already allowed.
>
> Is `if(const x = 5)` really that much of a stretch?
>
> To answer a concern about a function call like `myFunction(const x = 7)`, of
> course the scope of `x` would be where it is declared. It can't be anywhere
> else (like inside myFunction or something).
>
> On Thu, 22 Mar 2018 at 22:53 Isiah Meadows <[hidden email]> wrote:
>>
>> Probably true, more so than the `if (var ...)`/etc. (which can't be as
>> easily desugared). My `else` variant desugars more to something that
>> is also easily simulated, and it's a less common case:
>>
>> ```js
>> let foo = bar else return baz;
>>
>> // Desugared
>> let _tmp = bar;
>> if (tmp == null) return baz;
>> let foo = _tmp;
>> ```
>>
>> In this case, there's also the question of whether to require a
>> `return` in all code paths, which probably makes this a bit more
>> complicated than what would be worth for such a simple language
>> feature.
>> -----
>>
>> Isiah Meadows
>> [hidden email]
>>
>> Looking for web consulting? Or a new website?
>> Send me an email and we can get started.
>> www.isiahmeadows.com
>>
>>
>> On Thu, Mar 22, 2018 at 12:23 PM, Michael Luder-Rosefield
>> <[hidden email]> wrote:
>> > That strikes me as territory the 'do expression' proposal
>> > https://github.com/tc39/proposal-do-expressions is more fitted for:
>> >
>> >     const x = do { if (c) expr; else { ... } };
>> >
>> > What I'd like for this proposal is something that works consistently and
>> > obviously for all blocks with a parenthesised element to them. When
>> > they're
>> > formally separated by semi-colons, as in `for (a;b;c)`, each of `a,b,c`
>> > acts
>> > as an expression. Why not allow any of those expressions to be replaced
>> > by a
>> > statement block that acts like a do expression, each of which's scope is
>> > nested under the previous one and are available to the following block?
>> >
>> > That didn't come out very clearly, so let's try with an example:
>> >
>> >   for ({
>> >       let x = 1, y = 2;
>> >       console.log("I'll be printed every loop!");
>> >     }; {
>> >       let s = 'some string';
>> >       if (y%7 === 0) x === y;
>> >       else x < 1000;
>> >     }; {
>> >       let s = 'some other string';
>> >       x+=1;
>> >       if (y%3 === 0) y += 2;
>> >       else y += 1;
>> >     }) {
>> >       // whatever code here
>> >       // local scope hierarchy is
>> >       //   {
>> >       //     x,
>> >       //    y,
>> >       //    __SCOPE__: {
>> >       //      s: 'some string',
>> >       //      __SCOPE__: {
>> >       //        s: 'some other string'
>> >       //      }
>> >       //    }
>> >       //  }
>> >     }
>> >
>> > I'm just using some random logic in the blocks to illustrate the point:
>> > all
>> > the variables declared in the blocks are accessible in the for block,
>> > but
>> > the 'some string' `s` is masked by the 'some other string' `s` in the
>> > child
>> > scope. The termination condition in the second block can vary each loop,
>> > as
>> > can the iteration operation in the last block, and is simply the last
>> > value
>> > in the block as-per do expressions.
>> >
>> > On Thu, 22 Mar 2018 at 15:44 Mike Samuel <[hidden email]> wrote:
>> >>
>> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <[hidden email]>
>> >> wrote:
>> >>>
>> >>>
>> >>> I do have one other related thing I'd like to see: add a `let foo =
>> >>> expr() else { ... }` variant, with a line terminator restriction
>> >>> before the `else` so it can't be confused with an `else` within an
>> >>> `if`.
>> >>
>> >>
>> >> Making it a restricted production would solve the grammatical ambiguity
>> >> for existing code, but maybe in an errorprone way for future code:
>> >>
>> >>     if (c) let foo = expr() else { ... } // else attaches to let
>> >>     if (c) let foo = expr(); else { ... } // else attaches to if
>> >>
>> >>
>> >> Would the semantics differ from
>> >>
>> >>    let foo = expr() || ({} => { ... })()
>> >>
>> >> ?
>> >>
>> >>
>> >>
>> >>
>> >>>
>> >>>
>> >>> -----
>> >>>
>> >>> Isiah Meadows
>> >>> [hidden email]
>> >>>
>> >>> Looking for web consulting? Or a new website?
>> >>> Send me an email and we can get started.
>> >>> www.isiahmeadows.com
>> >>>
>> >>>
>> >>> On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <[hidden email]>
>> >>> wrote:
>> >>> > Not just let-scopes, but the introduction of `async/await` also
>> >>> > welcomes the introduction of if-scoped variables.
>> >>> >
>> >>> >     if (const data = await collection.find({}).toArray();
>> >>> > data.length >
>> >>> > 10)
>> >>> > {
>> >>> >         console.log(data);
>> >>> >     } else if (data.length > 0) {
>> >>> >         console.log(data);
>> >>> >     } else {
>> >>> >         console.log(data);
>> >>> >     }
>> >>> >
>> >>> > And, as mentioned by @jerry, this can be extended to `switch` and
>> >>> > `while`. Golang has `switch(;)` initialization too afaik.
>> >>> >
>> >>> >     switch( const today = new Date(); today.getDay() ) {
>> >>> >          case 0:
>> >>> >             console.log( "Don't work on %s", today.toString() );
>> >>> >             break;
>> >>> >     }
>> >>> >
>> >>> > `while` would be a bit unnecessary, due to the fact that it can be
>> >>> > replicated with `for( <assign>; <expression>; )`, but could be
>> >>> > available for consistency with `if` and `switch`.
>> >>> >
>> >>> > El mié., 21 mar. 2018 19:47, Mike Samuel <[hidden email]>
>> >>> > escribió:
>> >>> >>
>> >>> >>
>> >>> >>
>> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton
>> >>> >> <[hidden email]>
>> >>> >> wrote:
>> >>> >>>
>> >>> >>> Because block-level scoping is a very good way to avoid certain
>> >>> >>> bugs
>> >>> >>> and
>> >>> >>> is easier to reason about. Especially when considering project
>> >>> >>> successors.
>> >>> >>
>> >>> >>
>> >>> >> +1.  function-scoped variables in loop bodies caused tons of bugs
>> >>> >> before
>> >>> >> let-scoped variables and were a main motivating case.
>> >>> >>
>> >>> >> var i;
>> >>> >> for (i = 0; i < arr.length; ++i) {
>> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >>> >> }
>> >>> >>
>> >>> >> vs
>> >>> >>
>> >>> >> for (let i = 0; i < arr.length; ++i) {
>> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >>> >> }
>> >>> >>
>> >>> >> Yes, linters got pretty good at finding uses of closed-over
>> >>> >> variables
>> >>> >> modified in a loop, but the workarounds were not ideal.
>> >>> >>
>> >>> >> var i;
>> >>> >> for (i = 0; i < arr.length; ++i) {
>> >>> >>   f(function (i) { return function () { /* Do something with */
>> >>> >> arr[i]; }
>> >>> >> }(i));
>> >>> >> }
>> >>> >>
>> >>> >> Block scoping is just better for code that uses loops, variables,
>> >>> >> and
>> >>> >> function expressions.
>> >>> >>
>> >>> >> _______________________________________________
>> >>> >> 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
>> >>> >
>> >>
>> >> _______________________________________________
>> >> 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
>
>
> _______________________________________________
> 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: Proposal: if variable initialization

Naveen Chawla
I don't know why `foo(let x = 10)` would be a bad practice or hurt readability.

I find it perfectly readable and with obvious meaning!

```js
    foo(const x = 10)
    bar(x)
```

vs

```js
    const x = 10
    foo(x)
    bar(x)
```

I also find it "clean". So I guess these aren't really useful terms.

As for the `if(const x = 5)` being like `if(x = 5)` being confused with `if(x==5)`, `if(const x == 5)` would throw an error anyway.

On Fri, 23 Mar 2018 at 20:02 Rodrigo <[hidden email]> wrote:
@Naveen, I think it's best to avoid this road altogether and keep
initialization clean, even though assignment isn't.

The proposal is that given `for(;;)` hence `if(;)` instead of given
`x=y` hence `let x=y`.

But yes, `if( x = 5)` is already allowed, but it's confusing and hard to read.

Confusing on what is being compared on multiple statements: `if((const
x = 5, y = 10) > 0)`

Confusing when destructuring, on what's being compared: `if(let [x,y] = [1,2])`

Confusing when multiple statements: `if ((x = 10, y = 20) > 15)`

Looks like an error: `if( x = 5 )` versus `if( x == 5)`, did the
programmer forget the `=`?

And if you introduce nesting initializations everywhere outside the
`if`, that's basically an invitation for readability nightmare. `let`
and `const` anywhere introduce 2 conflicting best-practices:

- Rule 1: declare your variables that are used exclusively within `if`
blocks within the `if` parens

- Rule 2: don't declare variables within another statement (so that
people will refrain from doing `foo( let x=10 )`

Consider that, historically, other languages such as Perl allowed `if(
(my $x = 1) > 0)` and `foo( my $x = 100)` and became the ugly child of
power programming; whereas Golang, born much later, has limited
initializations to things such as `if( x:=1; x > 0)` and has kept
things quite minimalistic (and clear for the programmer).

```perl
# realworld example, hard to find variable declaration:

$redis->subscribe( 'queue', my $callback = sub {
    ...
});
```


On Fri, Mar 23, 2018 at 7:21 AM, Naveen Chawla <[hidden email]> wrote:
> I'm still not seeing a compelling case for not allowing `const` / `let`
> declarations to be evaluated as expressions. Or I've missed it.
>
> As was noted,
>
> `if(x = 5)` is already allowed.
>
> Is `if(const x = 5)` really that much of a stretch?
>
> To answer a concern about a function call like `myFunction(const x = 7)`, of
> course the scope of `x` would be where it is declared. It can't be anywhere
> else (like inside myFunction or something).
>
> On Thu, 22 Mar 2018 at 22:53 Isiah Meadows <[hidden email]> wrote:
>>
>> Probably true, more so than the `if (var ...)`/etc. (which can't be as
>> easily desugared). My `else` variant desugars more to something that
>> is also easily simulated, and it's a less common case:
>>
>> ```js
>> let foo = bar else return baz;
>>
>> // Desugared
>> let _tmp = bar;
>> if (tmp == null) return baz;
>> let foo = _tmp;
>> ```
>>
>> In this case, there's also the question of whether to require a
>> `return` in all code paths, which probably makes this a bit more
>> complicated than what would be worth for such a simple language
>> feature.
>> -----
>>
>> Isiah Meadows
>> [hidden email]
>>
>> Looking for web consulting? Or a new website?
>> Send me an email and we can get started.
>> www.isiahmeadows.com
>>
>>
>> On Thu, Mar 22, 2018 at 12:23 PM, Michael Luder-Rosefield
>> <[hidden email]> wrote:
>> > That strikes me as territory the 'do expression' proposal
>> > https://github.com/tc39/proposal-do-expressions is more fitted for:
>> >
>> >     const x = do { if (c) expr; else { ... } };
>> >
>> > What I'd like for this proposal is something that works consistently and
>> > obviously for all blocks with a parenthesised element to them. When
>> > they're
>> > formally separated by semi-colons, as in `for (a;b;c)`, each of `a,b,c`
>> > acts
>> > as an expression. Why not allow any of those expressions to be replaced
>> > by a
>> > statement block that acts like a do expression, each of which's scope is
>> > nested under the previous one and are available to the following block?
>> >
>> > That didn't come out very clearly, so let's try with an example:
>> >
>> >   for ({
>> >       let x = 1, y = 2;
>> >       console.log("I'll be printed every loop!");
>> >     }; {
>> >       let s = 'some string';
>> >       if (y%7 === 0) x === y;
>> >       else x < 1000;
>> >     }; {
>> >       let s = 'some other string';
>> >       x+=1;
>> >       if (y%3 === 0) y += 2;
>> >       else y += 1;
>> >     }) {
>> >       // whatever code here
>> >       // local scope hierarchy is
>> >       //   {
>> >       //     x,
>> >       //    y,
>> >       //    __SCOPE__: {
>> >       //      s: 'some string',
>> >       //      __SCOPE__: {
>> >       //        s: 'some other string'
>> >       //      }
>> >       //    }
>> >       //  }
>> >     }
>> >
>> > I'm just using some random logic in the blocks to illustrate the point:
>> > all
>> > the variables declared in the blocks are accessible in the for block,
>> > but
>> > the 'some string' `s` is masked by the 'some other string' `s` in the
>> > child
>> > scope. The termination condition in the second block can vary each loop,
>> > as
>> > can the iteration operation in the last block, and is simply the last
>> > value
>> > in the block as-per do expressions.
>> >
>> > On Thu, 22 Mar 2018 at 15:44 Mike Samuel <[hidden email]> wrote:
>> >>
>> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <[hidden email]>
>> >> wrote:
>> >>>
>> >>>
>> >>> I do have one other related thing I'd like to see: add a `let foo =
>> >>> expr() else { ... }` variant, with a line terminator restriction
>> >>> before the `else` so it can't be confused with an `else` within an
>> >>> `if`.
>> >>
>> >>
>> >> Making it a restricted production would solve the grammatical ambiguity
>> >> for existing code, but maybe in an errorprone way for future code:
>> >>
>> >>     if (c) let foo = expr() else { ... } // else attaches to let
>> >>     if (c) let foo = expr(); else { ... } // else attaches to if
>> >>
>> >>
>> >> Would the semantics differ from
>> >>
>> >>    let foo = expr() || ({} => { ... })()
>> >>
>> >> ?
>> >>
>> >>
>> >>
>> >>
>> >>>
>> >>>
>> >>> -----
>> >>>
>> >>> Isiah Meadows
>> >>> [hidden email]
>> >>>
>> >>> Looking for web consulting? Or a new website?
>> >>> Send me an email and we can get started.
>> >>> www.isiahmeadows.com
>> >>>
>> >>>
>> >>> On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <[hidden email]>
>> >>> wrote:
>> >>> > Not just let-scopes, but the introduction of `async/await` also
>> >>> > welcomes the introduction of if-scoped variables.
>> >>> >
>> >>> >     if (const data = await collection.find({}).toArray();
>> >>> > data.length >
>> >>> > 10)
>> >>> > {
>> >>> >         console.log(data);
>> >>> >     } else if (data.length > 0) {
>> >>> >         console.log(data);
>> >>> >     } else {
>> >>> >         console.log(data);
>> >>> >     }
>> >>> >
>> >>> > And, as mentioned by @jerry, this can be extended to `switch` and
>> >>> > `while`. Golang has `switch(;)` initialization too afaik.
>> >>> >
>> >>> >     switch( const today = new Date(); today.getDay() ) {
>> >>> >          case 0:
>> >>> >             console.log( "Don't work on %s", today.toString() );
>> >>> >             break;
>> >>> >     }
>> >>> >
>> >>> > `while` would be a bit unnecessary, due to the fact that it can be
>> >>> > replicated with `for( <assign>; <expression>; )`, but could be
>> >>> > available for consistency with `if` and `switch`.
>> >>> >
>> >>> > El mié., 21 mar. 2018 19:47, Mike Samuel <[hidden email]>
>> >>> > escribió:
>> >>> >>
>> >>> >>
>> >>> >>
>> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton
>> >>> >> <[hidden email]>
>> >>> >> wrote:
>> >>> >>>
>> >>> >>> Because block-level scoping is a very good way to avoid certain
>> >>> >>> bugs
>> >>> >>> and
>> >>> >>> is easier to reason about. Especially when considering project
>> >>> >>> successors.
>> >>> >>
>> >>> >>
>> >>> >> +1.  function-scoped variables in loop bodies caused tons of bugs
>> >>> >> before
>> >>> >> let-scoped variables and were a main motivating case.
>> >>> >>
>> >>> >> var i;
>> >>> >> for (i = 0; i < arr.length; ++i) {
>> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >>> >> }
>> >>> >>
>> >>> >> vs
>> >>> >>
>> >>> >> for (let i = 0; i < arr.length; ++i) {
>> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >>> >> }
>> >>> >>
>> >>> >> Yes, linters got pretty good at finding uses of closed-over
>> >>> >> variables
>> >>> >> modified in a loop, but the workarounds were not ideal.
>> >>> >>
>> >>> >> var i;
>> >>> >> for (i = 0; i < arr.length; ++i) {
>> >>> >>   f(function (i) { return function () { /* Do something with */
>> >>> >> arr[i]; }
>> >>> >> }(i));
>> >>> >> }
>> >>> >>
>> >>> >> Block scoping is just better for code that uses loops, variables,
>> >>> >> and
>> >>> >> function expressions.
>> >>> >>
>> >>> >> _______________________________________________
>> >>> >> 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
>> >>> >
>> >>
>> >> _______________________________________________
>> >> 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
>
>
> _______________________________________________
> 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: Proposal: if variable initialization

Isiah Meadows-2
I disagree, I feel it's too clever. It'd make sense in a control flow
statement where in the alternate branch, the value is
meaningless/useless/ineffable/etc. (and this is why `for` loops
commonly allow such syntax already), but in ordinary function calls,
it seems like it's just trying to golf the code without good reason.

It's not visually ambiguous, just pointless in my opinion (a solution
in search of a problem).

-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Sat, Mar 24, 2018 at 7:54 AM, Naveen Chawla <[hidden email]> wrote:

> I don't know why `foo(let x = 10)` would be a bad practice or hurt
> readability.
>
> I find it perfectly readable and with obvious meaning!
>
> ```js
>     foo(const x = 10)
>     bar(x)
> ```
>
> vs
>
> ```js
>     const x = 10
>     foo(x)
>     bar(x)
> ```
>
> I also find it "clean". So I guess these aren't really useful terms.
>
> As for the `if(const x = 5)` being like `if(x = 5)` being confused with
> `if(x==5)`, `if(const x == 5)` would throw an error anyway.
>
> On Fri, 23 Mar 2018 at 20:02 Rodrigo <[hidden email]> wrote:
>>
>> @Naveen, I think it's best to avoid this road altogether and keep
>> initialization clean, even though assignment isn't.
>>
>> The proposal is that given `for(;;)` hence `if(;)` instead of given
>> `x=y` hence `let x=y`.
>>
>> But yes, `if( x = 5)` is already allowed, but it's confusing and hard to
>> read.
>>
>> Confusing on what is being compared on multiple statements: `if((const
>> x = 5, y = 10) > 0)`
>>
>> Confusing when destructuring, on what's being compared: `if(let [x,y] =
>> [1,2])`
>>
>> Confusing when multiple statements: `if ((x = 10, y = 20) > 15)`
>>
>> Looks like an error: `if( x = 5 )` versus `if( x == 5)`, did the
>> programmer forget the `=`?
>>
>> And if you introduce nesting initializations everywhere outside the
>> `if`, that's basically an invitation for readability nightmare. `let`
>> and `const` anywhere introduce 2 conflicting best-practices:
>>
>> - Rule 1: declare your variables that are used exclusively within `if`
>> blocks within the `if` parens
>>
>> - Rule 2: don't declare variables within another statement (so that
>> people will refrain from doing `foo( let x=10 )`
>>
>> Consider that, historically, other languages such as Perl allowed `if(
>> (my $x = 1) > 0)` and `foo( my $x = 100)` and became the ugly child of
>> power programming; whereas Golang, born much later, has limited
>> initializations to things such as `if( x:=1; x > 0)` and has kept
>> things quite minimalistic (and clear for the programmer).
>>
>> ```perl
>> # realworld example, hard to find variable declaration:
>>
>> $redis->subscribe( 'queue', my $callback = sub {
>>     ...
>> });
>> ```
>>
>>
>> On Fri, Mar 23, 2018 at 7:21 AM, Naveen Chawla <[hidden email]>
>> wrote:
>> > I'm still not seeing a compelling case for not allowing `const` / `let`
>> > declarations to be evaluated as expressions. Or I've missed it.
>> >
>> > As was noted,
>> >
>> > `if(x = 5)` is already allowed.
>> >
>> > Is `if(const x = 5)` really that much of a stretch?
>> >
>> > To answer a concern about a function call like `myFunction(const x =
>> > 7)`, of
>> > course the scope of `x` would be where it is declared. It can't be
>> > anywhere
>> > else (like inside myFunction or something).
>> >
>> > On Thu, 22 Mar 2018 at 22:53 Isiah Meadows <[hidden email]>
>> > wrote:
>> >>
>> >> Probably true, more so than the `if (var ...)`/etc. (which can't be as
>> >> easily desugared). My `else` variant desugars more to something that
>> >> is also easily simulated, and it's a less common case:
>> >>
>> >> ```js
>> >> let foo = bar else return baz;
>> >>
>> >> // Desugared
>> >> let _tmp = bar;
>> >> if (tmp == null) return baz;
>> >> let foo = _tmp;
>> >> ```
>> >>
>> >> In this case, there's also the question of whether to require a
>> >> `return` in all code paths, which probably makes this a bit more
>> >> complicated than what would be worth for such a simple language
>> >> feature.
>> >> -----
>> >>
>> >> Isiah Meadows
>> >> [hidden email]
>> >>
>> >> Looking for web consulting? Or a new website?
>> >> Send me an email and we can get started.
>> >> www.isiahmeadows.com
>> >>
>> >>
>> >> On Thu, Mar 22, 2018 at 12:23 PM, Michael Luder-Rosefield
>> >> <[hidden email]> wrote:
>> >> > That strikes me as territory the 'do expression' proposal
>> >> > https://github.com/tc39/proposal-do-expressions is more fitted for:
>> >> >
>> >> >     const x = do { if (c) expr; else { ... } };
>> >> >
>> >> > What I'd like for this proposal is something that works consistently
>> >> > and
>> >> > obviously for all blocks with a parenthesised element to them. When
>> >> > they're
>> >> > formally separated by semi-colons, as in `for (a;b;c)`, each of
>> >> > `a,b,c`
>> >> > acts
>> >> > as an expression. Why not allow any of those expressions to be
>> >> > replaced
>> >> > by a
>> >> > statement block that acts like a do expression, each of which's scope
>> >> > is
>> >> > nested under the previous one and are available to the following
>> >> > block?
>> >> >
>> >> > That didn't come out very clearly, so let's try with an example:
>> >> >
>> >> >   for ({
>> >> >       let x = 1, y = 2;
>> >> >       console.log("I'll be printed every loop!");
>> >> >     }; {
>> >> >       let s = 'some string';
>> >> >       if (y%7 === 0) x === y;
>> >> >       else x < 1000;
>> >> >     }; {
>> >> >       let s = 'some other string';
>> >> >       x+=1;
>> >> >       if (y%3 === 0) y += 2;
>> >> >       else y += 1;
>> >> >     }) {
>> >> >       // whatever code here
>> >> >       // local scope hierarchy is
>> >> >       //   {
>> >> >       //     x,
>> >> >       //    y,
>> >> >       //    __SCOPE__: {
>> >> >       //      s: 'some string',
>> >> >       //      __SCOPE__: {
>> >> >       //        s: 'some other string'
>> >> >       //      }
>> >> >       //    }
>> >> >       //  }
>> >> >     }
>> >> >
>> >> > I'm just using some random logic in the blocks to illustrate the
>> >> > point:
>> >> > all
>> >> > the variables declared in the blocks are accessible in the for block,
>> >> > but
>> >> > the 'some string' `s` is masked by the 'some other string' `s` in the
>> >> > child
>> >> > scope. The termination condition in the second block can vary each
>> >> > loop,
>> >> > as
>> >> > can the iteration operation in the last block, and is simply the last
>> >> > value
>> >> > in the block as-per do expressions.
>> >> >
>> >> > On Thu, 22 Mar 2018 at 15:44 Mike Samuel <[hidden email]>
>> >> > wrote:
>> >> >>
>> >> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows
>> >> >> <[hidden email]>
>> >> >> wrote:
>> >> >>>
>> >> >>>
>> >> >>> I do have one other related thing I'd like to see: add a `let foo =
>> >> >>> expr() else { ... }` variant, with a line terminator restriction
>> >> >>> before the `else` so it can't be confused with an `else` within an
>> >> >>> `if`.
>> >> >>
>> >> >>
>> >> >> Making it a restricted production would solve the grammatical
>> >> >> ambiguity
>> >> >> for existing code, but maybe in an errorprone way for future code:
>> >> >>
>> >> >>     if (c) let foo = expr() else { ... } // else attaches to let
>> >> >>     if (c) let foo = expr(); else { ... } // else attaches to if
>> >> >>
>> >> >>
>> >> >> Would the semantics differ from
>> >> >>
>> >> >>    let foo = expr() || ({} => { ... })()
>> >> >>
>> >> >> ?
>> >> >>
>> >> >>
>> >> >>
>> >> >>
>> >> >>>
>> >> >>>
>> >> >>> -----
>> >> >>>
>> >> >>> Isiah Meadows
>> >> >>> [hidden email]
>> >> >>>
>> >> >>> Looking for web consulting? Or a new website?
>> >> >>> Send me an email and we can get started.
>> >> >>> www.isiahmeadows.com
>> >> >>>
>> >> >>>
>> >> >>> On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <[hidden email]>
>> >> >>> wrote:
>> >> >>> > Not just let-scopes, but the introduction of `async/await` also
>> >> >>> > welcomes the introduction of if-scoped variables.
>> >> >>> >
>> >> >>> >     if (const data = await collection.find({}).toArray();
>> >> >>> > data.length >
>> >> >>> > 10)
>> >> >>> > {
>> >> >>> >         console.log(data);
>> >> >>> >     } else if (data.length > 0) {
>> >> >>> >         console.log(data);
>> >> >>> >     } else {
>> >> >>> >         console.log(data);
>> >> >>> >     }
>> >> >>> >
>> >> >>> > And, as mentioned by @jerry, this can be extended to `switch` and
>> >> >>> > `while`. Golang has `switch(;)` initialization too afaik.
>> >> >>> >
>> >> >>> >     switch( const today = new Date(); today.getDay() ) {
>> >> >>> >          case 0:
>> >> >>> >             console.log( "Don't work on %s", today.toString() );
>> >> >>> >             break;
>> >> >>> >     }
>> >> >>> >
>> >> >>> > `while` would be a bit unnecessary, due to the fact that it can
>> >> >>> > be
>> >> >>> > replicated with `for( <assign>; <expression>; )`, but could be
>> >> >>> > available for consistency with `if` and `switch`.
>> >> >>> >
>> >> >>> > El mié., 21 mar. 2018 19:47, Mike Samuel <[hidden email]>
>> >> >>> > escribió:
>> >> >>> >>
>> >> >>> >>
>> >> >>> >>
>> >> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton
>> >> >>> >> <[hidden email]>
>> >> >>> >> wrote:
>> >> >>> >>>
>> >> >>> >>> Because block-level scoping is a very good way to avoid certain
>> >> >>> >>> bugs
>> >> >>> >>> and
>> >> >>> >>> is easier to reason about. Especially when considering project
>> >> >>> >>> successors.
>> >> >>> >>
>> >> >>> >>
>> >> >>> >> +1.  function-scoped variables in loop bodies caused tons of
>> >> >>> >> bugs
>> >> >>> >> before
>> >> >>> >> let-scoped variables and were a main motivating case.
>> >> >>> >>
>> >> >>> >> var i;
>> >> >>> >> for (i = 0; i < arr.length; ++i) {
>> >> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >> >>> >> }
>> >> >>> >>
>> >> >>> >> vs
>> >> >>> >>
>> >> >>> >> for (let i = 0; i < arr.length; ++i) {
>> >> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >> >>> >> }
>> >> >>> >>
>> >> >>> >> Yes, linters got pretty good at finding uses of closed-over
>> >> >>> >> variables
>> >> >>> >> modified in a loop, but the workarounds were not ideal.
>> >> >>> >>
>> >> >>> >> var i;
>> >> >>> >> for (i = 0; i < arr.length; ++i) {
>> >> >>> >>   f(function (i) { return function () { /* Do something with */
>> >> >>> >> arr[i]; }
>> >> >>> >> }(i));
>> >> >>> >> }
>> >> >>> >>
>> >> >>> >> Block scoping is just better for code that uses loops,
>> >> >>> >> variables,
>> >> >>> >> and
>> >> >>> >> function expressions.
>> >> >>> >>
>> >> >>> >> _______________________________________________
>> >> >>> >> 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
>> >> >>> >
>> >> >>
>> >> >> _______________________________________________
>> >> >> 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
>> >
>> >
>> > _______________________________________________
>> > 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: Proposal: if variable initialization

Naveen Chawla
I understand the fear about "bad code" potentially sprouting from it. I guess I'm not as bothered as long as I can do what I want. So it's a matter of how heavily weighted the "potential bad practice" concern is over developer power.

The advantage is that it's as powerful as the developer wants it to be, and makes the common cases in `if` and `while` easy to learn and do.

For example, you can do while( x > (const y = getYFromX(x) ) ), which none of the other ideas directly allow.

Which brings me to the next point. How would otherwise do this in a while loop? I presume the while(;) based initialization part would only operate at the start of the loop, to be consistent with for loops. So how would you make a scoped variable initialization on every iteration?

On Sun, 25 Mar 2018 at 03:21 Isiah Meadows <[hidden email]> wrote:
I disagree, I feel it's too clever. It'd make sense in a control flow
statement where in the alternate branch, the value is
meaningless/useless/ineffable/etc. (and this is why `for` loops
commonly allow such syntax already), but in ordinary function calls,
it seems like it's just trying to golf the code without good reason.

It's not visually ambiguous, just pointless in my opinion (a solution
in search of a problem).

-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Sat, Mar 24, 2018 at 7:54 AM, Naveen Chawla <[hidden email]> wrote:
> I don't know why `foo(let x = 10)` would be a bad practice or hurt
> readability.
>
> I find it perfectly readable and with obvious meaning!
>
> ```js
>     foo(const x = 10)
>     bar(x)
> ```
>
> vs
>
> ```js
>     const x = 10
>     foo(x)
>     bar(x)
> ```
>
> I also find it "clean". So I guess these aren't really useful terms.
>
> As for the `if(const x = 5)` being like `if(x = 5)` being confused with
> `if(x==5)`, `if(const x == 5)` would throw an error anyway.
>
> On Fri, 23 Mar 2018 at 20:02 Rodrigo <[hidden email]> wrote:
>>
>> @Naveen, I think it's best to avoid this road altogether and keep
>> initialization clean, even though assignment isn't.
>>
>> The proposal is that given `for(;;)` hence `if(;)` instead of given
>> `x=y` hence `let x=y`.
>>
>> But yes, `if( x = 5)` is already allowed, but it's confusing and hard to
>> read.
>>
>> Confusing on what is being compared on multiple statements: `if((const
>> x = 5, y = 10) > 0)`
>>
>> Confusing when destructuring, on what's being compared: `if(let [x,y] =
>> [1,2])`
>>
>> Confusing when multiple statements: `if ((x = 10, y = 20) > 15)`
>>
>> Looks like an error: `if( x = 5 )` versus `if( x == 5)`, did the
>> programmer forget the `=`?
>>
>> And if you introduce nesting initializations everywhere outside the
>> `if`, that's basically an invitation for readability nightmare. `let`
>> and `const` anywhere introduce 2 conflicting best-practices:
>>
>> - Rule 1: declare your variables that are used exclusively within `if`
>> blocks within the `if` parens
>>
>> - Rule 2: don't declare variables within another statement (so that
>> people will refrain from doing `foo( let x=10 )`
>>
>> Consider that, historically, other languages such as Perl allowed `if(
>> (my $x = 1) > 0)` and `foo( my $x = 100)` and became the ugly child of
>> power programming; whereas Golang, born much later, has limited
>> initializations to things such as `if( x:=1; x > 0)` and has kept
>> things quite minimalistic (and clear for the programmer).
>>
>> ```perl
>> # realworld example, hard to find variable declaration:
>>
>> $redis->subscribe( 'queue', my $callback = sub {
>>     ...
>> });
>> ```
>>
>>
>> On Fri, Mar 23, 2018 at 7:21 AM, Naveen Chawla <[hidden email]>
>> wrote:
>> > I'm still not seeing a compelling case for not allowing `const` / `let`
>> > declarations to be evaluated as expressions. Or I've missed it.
>> >
>> > As was noted,
>> >
>> > `if(x = 5)` is already allowed.
>> >
>> > Is `if(const x = 5)` really that much of a stretch?
>> >
>> > To answer a concern about a function call like `myFunction(const x =
>> > 7)`, of
>> > course the scope of `x` would be where it is declared. It can't be
>> > anywhere
>> > else (like inside myFunction or something).
>> >
>> > On Thu, 22 Mar 2018 at 22:53 Isiah Meadows <[hidden email]>
>> > wrote:
>> >>
>> >> Probably true, more so than the `if (var ...)`/etc. (which can't be as
>> >> easily desugared). My `else` variant desugars more to something that
>> >> is also easily simulated, and it's a less common case:
>> >>
>> >> ```js
>> >> let foo = bar else return baz;
>> >>
>> >> // Desugared
>> >> let _tmp = bar;
>> >> if (tmp == null) return baz;
>> >> let foo = _tmp;
>> >> ```
>> >>
>> >> In this case, there's also the question of whether to require a
>> >> `return` in all code paths, which probably makes this a bit more
>> >> complicated than what would be worth for such a simple language
>> >> feature.
>> >> -----
>> >>
>> >> Isiah Meadows
>> >> [hidden email]
>> >>
>> >> Looking for web consulting? Or a new website?
>> >> Send me an email and we can get started.
>> >> www.isiahmeadows.com
>> >>
>> >>
>> >> On Thu, Mar 22, 2018 at 12:23 PM, Michael Luder-Rosefield
>> >> <[hidden email]> wrote:
>> >> > That strikes me as territory the 'do expression' proposal
>> >> > https://github.com/tc39/proposal-do-expressions is more fitted for:
>> >> >
>> >> >     const x = do { if (c) expr; else { ... } };
>> >> >
>> >> > What I'd like for this proposal is something that works consistently
>> >> > and
>> >> > obviously for all blocks with a parenthesised element to them. When
>> >> > they're
>> >> > formally separated by semi-colons, as in `for (a;b;c)`, each of
>> >> > `a,b,c`
>> >> > acts
>> >> > as an expression. Why not allow any of those expressions to be
>> >> > replaced
>> >> > by a
>> >> > statement block that acts like a do expression, each of which's scope
>> >> > is
>> >> > nested under the previous one and are available to the following
>> >> > block?
>> >> >
>> >> > That didn't come out very clearly, so let's try with an example:
>> >> >
>> >> >   for ({
>> >> >       let x = 1, y = 2;
>> >> >       console.log("I'll be printed every loop!");
>> >> >     }; {
>> >> >       let s = 'some string';
>> >> >       if (y%7 === 0) x === y;
>> >> >       else x < 1000;
>> >> >     }; {
>> >> >       let s = 'some other string';
>> >> >       x+=1;
>> >> >       if (y%3 === 0) y += 2;
>> >> >       else y += 1;
>> >> >     }) {
>> >> >       // whatever code here
>> >> >       // local scope hierarchy is
>> >> >       //   {
>> >> >       //     x,
>> >> >       //    y,
>> >> >       //    __SCOPE__: {
>> >> >       //      s: 'some string',
>> >> >       //      __SCOPE__: {
>> >> >       //        s: 'some other string'
>> >> >       //      }
>> >> >       //    }
>> >> >       //  }
>> >> >     }
>> >> >
>> >> > I'm just using some random logic in the blocks to illustrate the
>> >> > point:
>> >> > all
>> >> > the variables declared in the blocks are accessible in the for block,
>> >> > but
>> >> > the 'some string' `s` is masked by the 'some other string' `s` in the
>> >> > child
>> >> > scope. The termination condition in the second block can vary each
>> >> > loop,
>> >> > as
>> >> > can the iteration operation in the last block, and is simply the last
>> >> > value
>> >> > in the block as-per do expressions.
>> >> >
>> >> > On Thu, 22 Mar 2018 at 15:44 Mike Samuel <[hidden email]>
>> >> > wrote:
>> >> >>
>> >> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows
>> >> >> <[hidden email]>
>> >> >> wrote:
>> >> >>>
>> >> >>>
>> >> >>> I do have one other related thing I'd like to see: add a `let foo =
>> >> >>> expr() else { ... }` variant, with a line terminator restriction
>> >> >>> before the `else` so it can't be confused with an `else` within an
>> >> >>> `if`.
>> >> >>
>> >> >>
>> >> >> Making it a restricted production would solve the grammatical
>> >> >> ambiguity
>> >> >> for existing code, but maybe in an errorprone way for future code:
>> >> >>
>> >> >>     if (c) let foo = expr() else { ... } // else attaches to let
>> >> >>     if (c) let foo = expr(); else { ... } // else attaches to if
>> >> >>
>> >> >>
>> >> >> Would the semantics differ from
>> >> >>
>> >> >>    let foo = expr() || ({} => { ... })()
>> >> >>
>> >> >> ?
>> >> >>
>> >> >>
>> >> >>
>> >> >>
>> >> >>>
>> >> >>>
>> >> >>> -----
>> >> >>>
>> >> >>> Isiah Meadows
>> >> >>> [hidden email]
>> >> >>>
>> >> >>> Looking for web consulting? Or a new website?
>> >> >>> Send me an email and we can get started.
>> >> >>> www.isiahmeadows.com
>> >> >>>
>> >> >>>
>> >> >>> On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <[hidden email]>
>> >> >>> wrote:
>> >> >>> > Not just let-scopes, but the introduction of `async/await` also
>> >> >>> > welcomes the introduction of if-scoped variables.
>> >> >>> >
>> >> >>> >     if (const data = await collection.find({}).toArray();
>> >> >>> > data.length >
>> >> >>> > 10)
>> >> >>> > {
>> >> >>> >         console.log(data);
>> >> >>> >     } else if (data.length > 0) {
>> >> >>> >         console.log(data);
>> >> >>> >     } else {
>> >> >>> >         console.log(data);
>> >> >>> >     }
>> >> >>> >
>> >> >>> > And, as mentioned by @jerry, this can be extended to `switch` and
>> >> >>> > `while`. Golang has `switch(;)` initialization too afaik.
>> >> >>> >
>> >> >>> >     switch( const today = new Date(); today.getDay() ) {
>> >> >>> >          case 0:
>> >> >>> >             console.log( "Don't work on %s", today.toString() );
>> >> >>> >             break;
>> >> >>> >     }
>> >> >>> >
>> >> >>> > `while` would be a bit unnecessary, due to the fact that it can
>> >> >>> > be
>> >> >>> > replicated with `for( <assign>; <expression>; )`, but could be
>> >> >>> > available for consistency with `if` and `switch`.
>> >> >>> >
>> >> >>> > El mié., 21 mar. 2018 19:47, Mike Samuel <[hidden email]>
>> >> >>> > escribió:
>> >> >>> >>
>> >> >>> >>
>> >> >>> >>
>> >> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton
>> >> >>> >> <[hidden email]>
>> >> >>> >> wrote:
>> >> >>> >>>
>> >> >>> >>> Because block-level scoping is a very good way to avoid certain
>> >> >>> >>> bugs
>> >> >>> >>> and
>> >> >>> >>> is easier to reason about. Especially when considering project
>> >> >>> >>> successors.
>> >> >>> >>
>> >> >>> >>
>> >> >>> >> +1.  function-scoped variables in loop bodies caused tons of
>> >> >>> >> bugs
>> >> >>> >> before
>> >> >>> >> let-scoped variables and were a main motivating case.
>> >> >>> >>
>> >> >>> >> var i;
>> >> >>> >> for (i = 0; i < arr.length; ++i) {
>> >> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >> >>> >> }
>> >> >>> >>
>> >> >>> >> vs
>> >> >>> >>
>> >> >>> >> for (let i = 0; i < arr.length; ++i) {
>> >> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >> >>> >> }
>> >> >>> >>
>> >> >>> >> Yes, linters got pretty good at finding uses of closed-over
>> >> >>> >> variables
>> >> >>> >> modified in a loop, but the workarounds were not ideal.
>> >> >>> >>
>> >> >>> >> var i;
>> >> >>> >> for (i = 0; i < arr.length; ++i) {
>> >> >>> >>   f(function (i) { return function () { /* Do something with */
>> >> >>> >> arr[i]; }
>> >> >>> >> }(i));
>> >> >>> >> }
>> >> >>> >>
>> >> >>> >> Block scoping is just better for code that uses loops,
>> >> >>> >> variables,
>> >> >>> >> and
>> >> >>> >> function expressions.
>> >> >>> >>
>> >> >>> >> _______________________________________________
>> >> >>> >> 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
>> >> >>> >
>> >> >>
>> >> >> _______________________________________________
>> >> >> 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
>> >
>> >
>> > _______________________________________________
>> > 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: Proposal: if variable initialization

Isiah Meadows-2
1. My concern with `while` is that it's a little too duplicative of
C-style `for` functionally (although it's not an exact partial clone).
That's why I backtracked on it right as I proposed it (within the same
email).
2. The scope would have been just like `if`, where it's scoped to the
body with an implicit inner block scope. Anything different would be
surprising and unintuitive.

-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Sun, Mar 25, 2018 at 12:55 AM, Naveen Chawla <[hidden email]> wrote:

> I understand the fear about "bad code" potentially sprouting from it. I
> guess I'm not as bothered as long as I can do what I want. So it's a matter
> of how heavily weighted the "potential bad practice" concern is over
> developer power.
>
> The advantage is that it's as powerful as the developer wants it to be, and
> makes the common cases in `if` and `while` easy to learn and do.
>
> For example, you can do while( x > (const y = getYFromX(x) ) ), which none
> of the other ideas directly allow.
>
> Which brings me to the next point. How would otherwise do this in a while
> loop? I presume the while(;) based initialization part would only operate at
> the start of the loop, to be consistent with for loops. So how would you
> make a scoped variable initialization on every iteration?
>
> On Sun, 25 Mar 2018 at 03:21 Isiah Meadows <[hidden email]> wrote:
>>
>> I disagree, I feel it's too clever. It'd make sense in a control flow
>> statement where in the alternate branch, the value is
>> meaningless/useless/ineffable/etc. (and this is why `for` loops
>> commonly allow such syntax already), but in ordinary function calls,
>> it seems like it's just trying to golf the code without good reason.
>>
>> It's not visually ambiguous, just pointless in my opinion (a solution
>> in search of a problem).
>>
>> -----
>>
>> Isiah Meadows
>> [hidden email]
>>
>> Looking for web consulting? Or a new website?
>> Send me an email and we can get started.
>> www.isiahmeadows.com
>>
>>
>> On Sat, Mar 24, 2018 at 7:54 AM, Naveen Chawla <[hidden email]>
>> wrote:
>> > I don't know why `foo(let x = 10)` would be a bad practice or hurt
>> > readability.
>> >
>> > I find it perfectly readable and with obvious meaning!
>> >
>> > ```js
>> >     foo(const x = 10)
>> >     bar(x)
>> > ```
>> >
>> > vs
>> >
>> > ```js
>> >     const x = 10
>> >     foo(x)
>> >     bar(x)
>> > ```
>> >
>> > I also find it "clean". So I guess these aren't really useful terms.
>> >
>> > As for the `if(const x = 5)` being like `if(x = 5)` being confused with
>> > `if(x==5)`, `if(const x == 5)` would throw an error anyway.
>> >
>> > On Fri, 23 Mar 2018 at 20:02 Rodrigo <[hidden email]> wrote:
>> >>
>> >> @Naveen, I think it's best to avoid this road altogether and keep
>> >> initialization clean, even though assignment isn't.
>> >>
>> >> The proposal is that given `for(;;)` hence `if(;)` instead of given
>> >> `x=y` hence `let x=y`.
>> >>
>> >> But yes, `if( x = 5)` is already allowed, but it's confusing and hard
>> >> to
>> >> read.
>> >>
>> >> Confusing on what is being compared on multiple statements: `if((const
>> >> x = 5, y = 10) > 0)`
>> >>
>> >> Confusing when destructuring, on what's being compared: `if(let [x,y] =
>> >> [1,2])`
>> >>
>> >> Confusing when multiple statements: `if ((x = 10, y = 20) > 15)`
>> >>
>> >> Looks like an error: `if( x = 5 )` versus `if( x == 5)`, did the
>> >> programmer forget the `=`?
>> >>
>> >> And if you introduce nesting initializations everywhere outside the
>> >> `if`, that's basically an invitation for readability nightmare. `let`
>> >> and `const` anywhere introduce 2 conflicting best-practices:
>> >>
>> >> - Rule 1: declare your variables that are used exclusively within `if`
>> >> blocks within the `if` parens
>> >>
>> >> - Rule 2: don't declare variables within another statement (so that
>> >> people will refrain from doing `foo( let x=10 )`
>> >>
>> >> Consider that, historically, other languages such as Perl allowed `if(
>> >> (my $x = 1) > 0)` and `foo( my $x = 100)` and became the ugly child of
>> >> power programming; whereas Golang, born much later, has limited
>> >> initializations to things such as `if( x:=1; x > 0)` and has kept
>> >> things quite minimalistic (and clear for the programmer).
>> >>
>> >> ```perl
>> >> # realworld example, hard to find variable declaration:
>> >>
>> >> $redis->subscribe( 'queue', my $callback = sub {
>> >>     ...
>> >> });
>> >> ```
>> >>
>> >>
>> >> On Fri, Mar 23, 2018 at 7:21 AM, Naveen Chawla <[hidden email]>
>> >> wrote:
>> >> > I'm still not seeing a compelling case for not allowing `const` /
>> >> > `let`
>> >> > declarations to be evaluated as expressions. Or I've missed it.
>> >> >
>> >> > As was noted,
>> >> >
>> >> > `if(x = 5)` is already allowed.
>> >> >
>> >> > Is `if(const x = 5)` really that much of a stretch?
>> >> >
>> >> > To answer a concern about a function call like `myFunction(const x =
>> >> > 7)`, of
>> >> > course the scope of `x` would be where it is declared. It can't be
>> >> > anywhere
>> >> > else (like inside myFunction or something).
>> >> >
>> >> > On Thu, 22 Mar 2018 at 22:53 Isiah Meadows <[hidden email]>
>> >> > wrote:
>> >> >>
>> >> >> Probably true, more so than the `if (var ...)`/etc. (which can't be
>> >> >> as
>> >> >> easily desugared). My `else` variant desugars more to something that
>> >> >> is also easily simulated, and it's a less common case:
>> >> >>
>> >> >> ```js
>> >> >> let foo = bar else return baz;
>> >> >>
>> >> >> // Desugared
>> >> >> let _tmp = bar;
>> >> >> if (tmp == null) return baz;
>> >> >> let foo = _tmp;
>> >> >> ```
>> >> >>
>> >> >> In this case, there's also the question of whether to require a
>> >> >> `return` in all code paths, which probably makes this a bit more
>> >> >> complicated than what would be worth for such a simple language
>> >> >> feature.
>> >> >> -----
>> >> >>
>> >> >> Isiah Meadows
>> >> >> [hidden email]
>> >> >>
>> >> >> Looking for web consulting? Or a new website?
>> >> >> Send me an email and we can get started.
>> >> >> www.isiahmeadows.com
>> >> >>
>> >> >>
>> >> >> On Thu, Mar 22, 2018 at 12:23 PM, Michael Luder-Rosefield
>> >> >> <[hidden email]> wrote:
>> >> >> > That strikes me as territory the 'do expression' proposal
>> >> >> > https://github.com/tc39/proposal-do-expressions is more fitted
>> >> >> > for:
>> >> >> >
>> >> >> >     const x = do { if (c) expr; else { ... } };
>> >> >> >
>> >> >> > What I'd like for this proposal is something that works
>> >> >> > consistently
>> >> >> > and
>> >> >> > obviously for all blocks with a parenthesised element to them.
>> >> >> > When
>> >> >> > they're
>> >> >> > formally separated by semi-colons, as in `for (a;b;c)`, each of
>> >> >> > `a,b,c`
>> >> >> > acts
>> >> >> > as an expression. Why not allow any of those expressions to be
>> >> >> > replaced
>> >> >> > by a
>> >> >> > statement block that acts like a do expression, each of which's
>> >> >> > scope
>> >> >> > is
>> >> >> > nested under the previous one and are available to the following
>> >> >> > block?
>> >> >> >
>> >> >> > That didn't come out very clearly, so let's try with an example:
>> >> >> >
>> >> >> >   for ({
>> >> >> >       let x = 1, y = 2;
>> >> >> >       console.log("I'll be printed every loop!");
>> >> >> >     }; {
>> >> >> >       let s = 'some string';
>> >> >> >       if (y%7 === 0) x === y;
>> >> >> >       else x < 1000;
>> >> >> >     }; {
>> >> >> >       let s = 'some other string';
>> >> >> >       x+=1;
>> >> >> >       if (y%3 === 0) y += 2;
>> >> >> >       else y += 1;
>> >> >> >     }) {
>> >> >> >       // whatever code here
>> >> >> >       // local scope hierarchy is
>> >> >> >       //   {
>> >> >> >       //     x,
>> >> >> >       //    y,
>> >> >> >       //    __SCOPE__: {
>> >> >> >       //      s: 'some string',
>> >> >> >       //      __SCOPE__: {
>> >> >> >       //        s: 'some other string'
>> >> >> >       //      }
>> >> >> >       //    }
>> >> >> >       //  }
>> >> >> >     }
>> >> >> >
>> >> >> > I'm just using some random logic in the blocks to illustrate the
>> >> >> > point:
>> >> >> > all
>> >> >> > the variables declared in the blocks are accessible in the for
>> >> >> > block,
>> >> >> > but
>> >> >> > the 'some string' `s` is masked by the 'some other string' `s` in
>> >> >> > the
>> >> >> > child
>> >> >> > scope. The termination condition in the second block can vary each
>> >> >> > loop,
>> >> >> > as
>> >> >> > can the iteration operation in the last block, and is simply the
>> >> >> > last
>> >> >> > value
>> >> >> > in the block as-per do expressions.
>> >> >> >
>> >> >> > On Thu, 22 Mar 2018 at 15:44 Mike Samuel <[hidden email]>
>> >> >> > wrote:
>> >> >> >>
>> >> >> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows
>> >> >> >> <[hidden email]>
>> >> >> >> wrote:
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> I do have one other related thing I'd like to see: add a `let
>> >> >> >>> foo =
>> >> >> >>> expr() else { ... }` variant, with a line terminator restriction
>> >> >> >>> before the `else` so it can't be confused with an `else` within
>> >> >> >>> an
>> >> >> >>> `if`.
>> >> >> >>
>> >> >> >>
>> >> >> >> Making it a restricted production would solve the grammatical
>> >> >> >> ambiguity
>> >> >> >> for existing code, but maybe in an errorprone way for future
>> >> >> >> code:
>> >> >> >>
>> >> >> >>     if (c) let foo = expr() else { ... } // else attaches to let
>> >> >> >>     if (c) let foo = expr(); else { ... } // else attaches to if
>> >> >> >>
>> >> >> >>
>> >> >> >> Would the semantics differ from
>> >> >> >>
>> >> >> >>    let foo = expr() || ({} => { ... })()
>> >> >> >>
>> >> >> >> ?
>> >> >> >>
>> >> >> >>
>> >> >> >>
>> >> >> >>
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> -----
>> >> >> >>>
>> >> >> >>> Isiah Meadows
>> >> >> >>> [hidden email]
>> >> >> >>>
>> >> >> >>> Looking for web consulting? Or a new website?
>> >> >> >>> Send me an email and we can get started.
>> >> >> >>> www.isiahmeadows.com
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <[hidden email]>
>> >> >> >>> wrote:
>> >> >> >>> > Not just let-scopes, but the introduction of `async/await`
>> >> >> >>> > also
>> >> >> >>> > welcomes the introduction of if-scoped variables.
>> >> >> >>> >
>> >> >> >>> >     if (const data = await collection.find({}).toArray();
>> >> >> >>> > data.length >
>> >> >> >>> > 10)
>> >> >> >>> > {
>> >> >> >>> >         console.log(data);
>> >> >> >>> >     } else if (data.length > 0) {
>> >> >> >>> >         console.log(data);
>> >> >> >>> >     } else {
>> >> >> >>> >         console.log(data);
>> >> >> >>> >     }
>> >> >> >>> >
>> >> >> >>> > And, as mentioned by @jerry, this can be extended to `switch`
>> >> >> >>> > and
>> >> >> >>> > `while`. Golang has `switch(;)` initialization too afaik.
>> >> >> >>> >
>> >> >> >>> >     switch( const today = new Date(); today.getDay() ) {
>> >> >> >>> >          case 0:
>> >> >> >>> >             console.log( "Don't work on %s", today.toString()
>> >> >> >>> > );
>> >> >> >>> >             break;
>> >> >> >>> >     }
>> >> >> >>> >
>> >> >> >>> > `while` would be a bit unnecessary, due to the fact that it
>> >> >> >>> > can
>> >> >> >>> > be
>> >> >> >>> > replicated with `for( <assign>; <expression>; )`, but could be
>> >> >> >>> > available for consistency with `if` and `switch`.
>> >> >> >>> >
>> >> >> >>> > El mié., 21 mar. 2018 19:47, Mike Samuel
>> >> >> >>> > <[hidden email]>
>> >> >> >>> > escribió:
>> >> >> >>> >>
>> >> >> >>> >>
>> >> >> >>> >>
>> >> >> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton
>> >> >> >>> >> <[hidden email]>
>> >> >> >>> >> wrote:
>> >> >> >>> >>>
>> >> >> >>> >>> Because block-level scoping is a very good way to avoid
>> >> >> >>> >>> certain
>> >> >> >>> >>> bugs
>> >> >> >>> >>> and
>> >> >> >>> >>> is easier to reason about. Especially when considering
>> >> >> >>> >>> project
>> >> >> >>> >>> successors.
>> >> >> >>> >>
>> >> >> >>> >>
>> >> >> >>> >> +1.  function-scoped variables in loop bodies caused tons of
>> >> >> >>> >> bugs
>> >> >> >>> >> before
>> >> >> >>> >> let-scoped variables and were a main motivating case.
>> >> >> >>> >>
>> >> >> >>> >> var i;
>> >> >> >>> >> for (i = 0; i < arr.length; ++i) {
>> >> >> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >> >> >>> >> }
>> >> >> >>> >>
>> >> >> >>> >> vs
>> >> >> >>> >>
>> >> >> >>> >> for (let i = 0; i < arr.length; ++i) {
>> >> >> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >> >> >>> >> }
>> >> >> >>> >>
>> >> >> >>> >> Yes, linters got pretty good at finding uses of closed-over
>> >> >> >>> >> variables
>> >> >> >>> >> modified in a loop, but the workarounds were not ideal.
>> >> >> >>> >>
>> >> >> >>> >> var i;
>> >> >> >>> >> for (i = 0; i < arr.length; ++i) {
>> >> >> >>> >>   f(function (i) { return function () { /* Do something with
>> >> >> >>> >> */
>> >> >> >>> >> arr[i]; }
>> >> >> >>> >> }(i));
>> >> >> >>> >> }
>> >> >> >>> >>
>> >> >> >>> >> Block scoping is just better for code that uses loops,
>> >> >> >>> >> variables,
>> >> >> >>> >> and
>> >> >> >>> >> function expressions.
>> >> >> >>> >>
>> >> >> >>> >> _______________________________________________
>> >> >> >>> >> 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
>> >> >> >>> >
>> >> >> >>
>> >> >> >> _______________________________________________
>> >> >> >> 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
>> >> >
>> >> >
>> >> > _______________________________________________
>> >> > 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: Proposal: if variable initialization

Naveen Chawla
Obviously scoped, agreed, but again how would you allow scoped initialization upon each iteration, or is it your preference not to allow that? (again, initializers-as-expressions allows that, despite the other concerns).

On Sun, 25 Mar 2018 at 10:57 Isiah Meadows <[hidden email]> wrote:
1. My concern with `while` is that it's a little too duplicative of
C-style `for` functionally (although it's not an exact partial clone).
That's why I backtracked on it right as I proposed it (within the same
email).
2. The scope would have been just like `if`, where it's scoped to the
body with an implicit inner block scope. Anything different would be
surprising and unintuitive.

-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Sun, Mar 25, 2018 at 12:55 AM, Naveen Chawla <[hidden email]> wrote:
> I understand the fear about "bad code" potentially sprouting from it. I
> guess I'm not as bothered as long as I can do what I want. So it's a matter
> of how heavily weighted the "potential bad practice" concern is over
> developer power.
>
> The advantage is that it's as powerful as the developer wants it to be, and
> makes the common cases in `if` and `while` easy to learn and do.
>
> For example, you can do while( x > (const y = getYFromX(x) ) ), which none
> of the other ideas directly allow.
>
> Which brings me to the next point. How would otherwise do this in a while
> loop? I presume the while(;) based initialization part would only operate at
> the start of the loop, to be consistent with for loops. So how would you
> make a scoped variable initialization on every iteration?
>
> On Sun, 25 Mar 2018 at 03:21 Isiah Meadows <[hidden email]> wrote:
>>
>> I disagree, I feel it's too clever. It'd make sense in a control flow
>> statement where in the alternate branch, the value is
>> meaningless/useless/ineffable/etc. (and this is why `for` loops
>> commonly allow such syntax already), but in ordinary function calls,
>> it seems like it's just trying to golf the code without good reason.
>>
>> It's not visually ambiguous, just pointless in my opinion (a solution
>> in search of a problem).
>>
>> -----
>>
>> Isiah Meadows
>> [hidden email]
>>
>> Looking for web consulting? Or a new website?
>> Send me an email and we can get started.
>> www.isiahmeadows.com
>>
>>
>> On Sat, Mar 24, 2018 at 7:54 AM, Naveen Chawla <[hidden email]>
>> wrote:
>> > I don't know why `foo(let x = 10)` would be a bad practice or hurt
>> > readability.
>> >
>> > I find it perfectly readable and with obvious meaning!
>> >
>> > ```js
>> >     foo(const x = 10)
>> >     bar(x)
>> > ```
>> >
>> > vs
>> >
>> > ```js
>> >     const x = 10
>> >     foo(x)
>> >     bar(x)
>> > ```
>> >
>> > I also find it "clean". So I guess these aren't really useful terms.
>> >
>> > As for the `if(const x = 5)` being like `if(x = 5)` being confused with
>> > `if(x==5)`, `if(const x == 5)` would throw an error anyway.
>> >
>> > On Fri, 23 Mar 2018 at 20:02 Rodrigo <[hidden email]> wrote:
>> >>
>> >> @Naveen, I think it's best to avoid this road altogether and keep
>> >> initialization clean, even though assignment isn't.
>> >>
>> >> The proposal is that given `for(;;)` hence `if(;)` instead of given
>> >> `x=y` hence `let x=y`.
>> >>
>> >> But yes, `if( x = 5)` is already allowed, but it's confusing and hard
>> >> to
>> >> read.
>> >>
>> >> Confusing on what is being compared on multiple statements: `if((const
>> >> x = 5, y = 10) > 0)`
>> >>
>> >> Confusing when destructuring, on what's being compared: `if(let [x,y] =
>> >> [1,2])`
>> >>
>> >> Confusing when multiple statements: `if ((x = 10, y = 20) > 15)`
>> >>
>> >> Looks like an error: `if( x = 5 )` versus `if( x == 5)`, did the
>> >> programmer forget the `=`?
>> >>
>> >> And if you introduce nesting initializations everywhere outside the
>> >> `if`, that's basically an invitation for readability nightmare. `let`
>> >> and `const` anywhere introduce 2 conflicting best-practices:
>> >>
>> >> - Rule 1: declare your variables that are used exclusively within `if`
>> >> blocks within the `if` parens
>> >>
>> >> - Rule 2: don't declare variables within another statement (so that
>> >> people will refrain from doing `foo( let x=10 )`
>> >>
>> >> Consider that, historically, other languages such as Perl allowed `if(
>> >> (my $x = 1) > 0)` and `foo( my $x = 100)` and became the ugly child of
>> >> power programming; whereas Golang, born much later, has limited
>> >> initializations to things such as `if( x:=1; x > 0)` and has kept
>> >> things quite minimalistic (and clear for the programmer).
>> >>
>> >> ```perl
>> >> # realworld example, hard to find variable declaration:
>> >>
>> >> $redis->subscribe( 'queue', my $callback = sub {
>> >>     ...
>> >> });
>> >> ```
>> >>
>> >>
>> >> On Fri, Mar 23, 2018 at 7:21 AM, Naveen Chawla <[hidden email]>
>> >> wrote:
>> >> > I'm still not seeing a compelling case for not allowing `const` /
>> >> > `let`
>> >> > declarations to be evaluated as expressions. Or I've missed it.
>> >> >
>> >> > As was noted,
>> >> >
>> >> > `if(x = 5)` is already allowed.
>> >> >
>> >> > Is `if(const x = 5)` really that much of a stretch?
>> >> >
>> >> > To answer a concern about a function call like `myFunction(const x =
>> >> > 7)`, of
>> >> > course the scope of `x` would be where it is declared. It can't be
>> >> > anywhere
>> >> > else (like inside myFunction or something).
>> >> >
>> >> > On Thu, 22 Mar 2018 at 22:53 Isiah Meadows <[hidden email]>
>> >> > wrote:
>> >> >>
>> >> >> Probably true, more so than the `if (var ...)`/etc. (which can't be
>> >> >> as
>> >> >> easily desugared). My `else` variant desugars more to something that
>> >> >> is also easily simulated, and it's a less common case:
>> >> >>
>> >> >> ```js
>> >> >> let foo = bar else return baz;
>> >> >>
>> >> >> // Desugared
>> >> >> let _tmp = bar;
>> >> >> if (tmp == null) return baz;
>> >> >> let foo = _tmp;
>> >> >> ```
>> >> >>
>> >> >> In this case, there's also the question of whether to require a
>> >> >> `return` in all code paths, which probably makes this a bit more
>> >> >> complicated than what would be worth for such a simple language
>> >> >> feature.
>> >> >> -----
>> >> >>
>> >> >> Isiah Meadows
>> >> >> [hidden email]
>> >> >>
>> >> >> Looking for web consulting? Or a new website?
>> >> >> Send me an email and we can get started.
>> >> >> www.isiahmeadows.com
>> >> >>
>> >> >>
>> >> >> On Thu, Mar 22, 2018 at 12:23 PM, Michael Luder-Rosefield
>> >> >> <[hidden email]> wrote:
>> >> >> > That strikes me as territory the 'do expression' proposal
>> >> >> > https://github.com/tc39/proposal-do-expressions is more fitted
>> >> >> > for:
>> >> >> >
>> >> >> >     const x = do { if (c) expr; else { ... } };
>> >> >> >
>> >> >> > What I'd like for this proposal is something that works
>> >> >> > consistently
>> >> >> > and
>> >> >> > obviously for all blocks with a parenthesised element to them.
>> >> >> > When
>> >> >> > they're
>> >> >> > formally separated by semi-colons, as in `for (a;b;c)`, each of
>> >> >> > `a,b,c`
>> >> >> > acts
>> >> >> > as an expression. Why not allow any of those expressions to be
>> >> >> > replaced
>> >> >> > by a
>> >> >> > statement block that acts like a do expression, each of which's
>> >> >> > scope
>> >> >> > is
>> >> >> > nested under the previous one and are available to the following
>> >> >> > block?
>> >> >> >
>> >> >> > That didn't come out very clearly, so let's try with an example:
>> >> >> >
>> >> >> >   for ({
>> >> >> >       let x = 1, y = 2;
>> >> >> >       console.log("I'll be printed every loop!");
>> >> >> >     }; {
>> >> >> >       let s = 'some string';
>> >> >> >       if (y%7 === 0) x === y;
>> >> >> >       else x < 1000;
>> >> >> >     }; {
>> >> >> >       let s = 'some other string';
>> >> >> >       x+=1;
>> >> >> >       if (y%3 === 0) y += 2;
>> >> >> >       else y += 1;
>> >> >> >     }) {
>> >> >> >       // whatever code here
>> >> >> >       // local scope hierarchy is
>> >> >> >       //   {
>> >> >> >       //     x,
>> >> >> >       //    y,
>> >> >> >       //    __SCOPE__: {
>> >> >> >       //      s: 'some string',
>> >> >> >       //      __SCOPE__: {
>> >> >> >       //        s: 'some other string'
>> >> >> >       //      }
>> >> >> >       //    }
>> >> >> >       //  }
>> >> >> >     }
>> >> >> >
>> >> >> > I'm just using some random logic in the blocks to illustrate the
>> >> >> > point:
>> >> >> > all
>> >> >> > the variables declared in the blocks are accessible in the for
>> >> >> > block,
>> >> >> > but
>> >> >> > the 'some string' `s` is masked by the 'some other string' `s` in
>> >> >> > the
>> >> >> > child
>> >> >> > scope. The termination condition in the second block can vary each
>> >> >> > loop,
>> >> >> > as
>> >> >> > can the iteration operation in the last block, and is simply the
>> >> >> > last
>> >> >> > value
>> >> >> > in the block as-per do expressions.
>> >> >> >
>> >> >> > On Thu, 22 Mar 2018 at 15:44 Mike Samuel <[hidden email]>
>> >> >> > wrote:
>> >> >> >>
>> >> >> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows
>> >> >> >> <[hidden email]>
>> >> >> >> wrote:
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> I do have one other related thing I'd like to see: add a `let
>> >> >> >>> foo =
>> >> >> >>> expr() else { ... }` variant, with a line terminator restriction
>> >> >> >>> before the `else` so it can't be confused with an `else` within
>> >> >> >>> an
>> >> >> >>> `if`.
>> >> >> >>
>> >> >> >>
>> >> >> >> Making it a restricted production would solve the grammatical
>> >> >> >> ambiguity
>> >> >> >> for existing code, but maybe in an errorprone way for future
>> >> >> >> code:
>> >> >> >>
>> >> >> >>     if (c) let foo = expr() else { ... } // else attaches to let
>> >> >> >>     if (c) let foo = expr(); else { ... } // else attaches to if
>> >> >> >>
>> >> >> >>
>> >> >> >> Would the semantics differ from
>> >> >> >>
>> >> >> >>    let foo = expr() || ({} => { ... })()
>> >> >> >>
>> >> >> >> ?
>> >> >> >>
>> >> >> >>
>> >> >> >>
>> >> >> >>
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> -----
>> >> >> >>>
>> >> >> >>> Isiah Meadows
>> >> >> >>> [hidden email]
>> >> >> >>>
>> >> >> >>> Looking for web consulting? Or a new website?
>> >> >> >>> Send me an email and we can get started.
>> >> >> >>> www.isiahmeadows.com
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <[hidden email]>
>> >> >> >>> wrote:
>> >> >> >>> > Not just let-scopes, but the introduction of `async/await`
>> >> >> >>> > also
>> >> >> >>> > welcomes the introduction of if-scoped variables.
>> >> >> >>> >
>> >> >> >>> >     if (const data = await collection.find({}).toArray();
>> >> >> >>> > data.length >
>> >> >> >>> > 10)
>> >> >> >>> > {
>> >> >> >>> >         console.log(data);
>> >> >> >>> >     } else if (data.length > 0) {
>> >> >> >>> >         console.log(data);
>> >> >> >>> >     } else {
>> >> >> >>> >         console.log(data);
>> >> >> >>> >     }
>> >> >> >>> >
>> >> >> >>> > And, as mentioned by @jerry, this can be extended to `switch`
>> >> >> >>> > and
>> >> >> >>> > `while`. Golang has `switch(;)` initialization too afaik.
>> >> >> >>> >
>> >> >> >>> >     switch( const today = new Date(); today.getDay() ) {
>> >> >> >>> >          case 0:
>> >> >> >>> >             console.log( "Don't work on %s", today.toString()
>> >> >> >>> > );
>> >> >> >>> >             break;
>> >> >> >>> >     }
>> >> >> >>> >
>> >> >> >>> > `while` would be a bit unnecessary, due to the fact that it
>> >> >> >>> > can
>> >> >> >>> > be
>> >> >> >>> > replicated with `for( <assign>; <expression>; )`, but could be
>> >> >> >>> > available for consistency with `if` and `switch`.
>> >> >> >>> >
>> >> >> >>> > El mié., 21 mar. 2018 19:47, Mike Samuel
>> >> >> >>> > <[hidden email]>
>> >> >> >>> > escribió:
>> >> >> >>> >>
>> >> >> >>> >>
>> >> >> >>> >>
>> >> >> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton
>> >> >> >>> >> <[hidden email]>
>> >> >> >>> >> wrote:
>> >> >> >>> >>>
>> >> >> >>> >>> Because block-level scoping is a very good way to avoid
>> >> >> >>> >>> certain
>> >> >> >>> >>> bugs
>> >> >> >>> >>> and
>> >> >> >>> >>> is easier to reason about. Especially when considering
>> >> >> >>> >>> project
>> >> >> >>> >>> successors.
>> >> >> >>> >>
>> >> >> >>> >>
>> >> >> >>> >> +1.  function-scoped variables in loop bodies caused tons of
>> >> >> >>> >> bugs
>> >> >> >>> >> before
>> >> >> >>> >> let-scoped variables and were a main motivating case.
>> >> >> >>> >>
>> >> >> >>> >> var i;
>> >> >> >>> >> for (i = 0; i < arr.length; ++i) {
>> >> >> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >> >> >>> >> }
>> >> >> >>> >>
>> >> >> >>> >> vs
>> >> >> >>> >>
>> >> >> >>> >> for (let i = 0; i < arr.length; ++i) {
>> >> >> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >> >> >>> >> }
>> >> >> >>> >>
>> >> >> >>> >> Yes, linters got pretty good at finding uses of closed-over
>> >> >> >>> >> variables
>> >> >> >>> >> modified in a loop, but the workarounds were not ideal.
>> >> >> >>> >>
>> >> >> >>> >> var i;
>> >> >> >>> >> for (i = 0; i < arr.length; ++i) {
>> >> >> >>> >>   f(function (i) { return function () { /* Do something with
>> >> >> >>> >> */
>> >> >> >>> >> arr[i]; }
>> >> >> >>> >> }(i));
>> >> >> >>> >> }
>> >> >> >>> >>
>> >> >> >>> >> Block scoping is just better for code that uses loops,
>> >> >> >>> >> variables,
>> >> >> >>> >> and
>> >> >> >>> >> function expressions.
>> >> >> >>> >>
>> >> >> >>> >> _______________________________________________
>> >> >> >>> >> 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
>> >> >> >>> >
>> >> >> >>
>> >> >> >> _______________________________________________
>> >> >> >> 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
>> >> >
>> >> >
>> >> > _______________________________________________
>> >> > 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: Proposal: if variable initialization

Isiah Meadows-2
Per-iteration scoping would work just as it does with `for (const foo
of bar) { ... }` now, and if it were to make it in (I'm mildly against
the feature, BTW), I'd prefer it to be per-iteration like that.
-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Sun, Mar 25, 2018 at 4:40 AM, Naveen Chawla <[hidden email]> wrote:

> Obviously scoped, agreed, but again how would you allow scoped
> initialization upon each iteration, or is it your preference not to allow
> that? (again, initializers-as-expressions allows that, despite the other
> concerns).
>
> On Sun, 25 Mar 2018 at 10:57 Isiah Meadows <[hidden email]> wrote:
>>
>> 1. My concern with `while` is that it's a little too duplicative of
>> C-style `for` functionally (although it's not an exact partial clone).
>> That's why I backtracked on it right as I proposed it (within the same
>> email).
>> 2. The scope would have been just like `if`, where it's scoped to the
>> body with an implicit inner block scope. Anything different would be
>> surprising and unintuitive.
>>
>> -----
>>
>> Isiah Meadows
>> [hidden email]
>>
>> Looking for web consulting? Or a new website?
>> Send me an email and we can get started.
>> www.isiahmeadows.com
>>
>>
>> On Sun, Mar 25, 2018 at 12:55 AM, Naveen Chawla <[hidden email]>
>> wrote:
>> > I understand the fear about "bad code" potentially sprouting from it. I
>> > guess I'm not as bothered as long as I can do what I want. So it's a
>> > matter
>> > of how heavily weighted the "potential bad practice" concern is over
>> > developer power.
>> >
>> > The advantage is that it's as powerful as the developer wants it to be,
>> > and
>> > makes the common cases in `if` and `while` easy to learn and do.
>> >
>> > For example, you can do while( x > (const y = getYFromX(x) ) ), which
>> > none
>> > of the other ideas directly allow.
>> >
>> > Which brings me to the next point. How would otherwise do this in a
>> > while
>> > loop? I presume the while(;) based initialization part would only
>> > operate at
>> > the start of the loop, to be consistent with for loops. So how would you
>> > make a scoped variable initialization on every iteration?
>> >
>> > On Sun, 25 Mar 2018 at 03:21 Isiah Meadows <[hidden email]>
>> > wrote:
>> >>
>> >> I disagree, I feel it's too clever. It'd make sense in a control flow
>> >> statement where in the alternate branch, the value is
>> >> meaningless/useless/ineffable/etc. (and this is why `for` loops
>> >> commonly allow such syntax already), but in ordinary function calls,
>> >> it seems like it's just trying to golf the code without good reason.
>> >>
>> >> It's not visually ambiguous, just pointless in my opinion (a solution
>> >> in search of a problem).
>> >>
>> >> -----
>> >>
>> >> Isiah Meadows
>> >> [hidden email]
>> >>
>> >> Looking for web consulting? Or a new website?
>> >> Send me an email and we can get started.
>> >> www.isiahmeadows.com
>> >>
>> >>
>> >> On Sat, Mar 24, 2018 at 7:54 AM, Naveen Chawla <[hidden email]>
>> >> wrote:
>> >> > I don't know why `foo(let x = 10)` would be a bad practice or hurt
>> >> > readability.
>> >> >
>> >> > I find it perfectly readable and with obvious meaning!
>> >> >
>> >> > ```js
>> >> >     foo(const x = 10)
>> >> >     bar(x)
>> >> > ```
>> >> >
>> >> > vs
>> >> >
>> >> > ```js
>> >> >     const x = 10
>> >> >     foo(x)
>> >> >     bar(x)
>> >> > ```
>> >> >
>> >> > I also find it "clean". So I guess these aren't really useful terms.
>> >> >
>> >> > As for the `if(const x = 5)` being like `if(x = 5)` being confused
>> >> > with
>> >> > `if(x==5)`, `if(const x == 5)` would throw an error anyway.
>> >> >
>> >> > On Fri, 23 Mar 2018 at 20:02 Rodrigo <[hidden email]> wrote:
>> >> >>
>> >> >> @Naveen, I think it's best to avoid this road altogether and keep
>> >> >> initialization clean, even though assignment isn't.
>> >> >>
>> >> >> The proposal is that given `for(;;)` hence `if(;)` instead of given
>> >> >> `x=y` hence `let x=y`.
>> >> >>
>> >> >> But yes, `if( x = 5)` is already allowed, but it's confusing and
>> >> >> hard
>> >> >> to
>> >> >> read.
>> >> >>
>> >> >> Confusing on what is being compared on multiple statements:
>> >> >> `if((const
>> >> >> x = 5, y = 10) > 0)`
>> >> >>
>> >> >> Confusing when destructuring, on what's being compared: `if(let
>> >> >> [x,y] =
>> >> >> [1,2])`
>> >> >>
>> >> >> Confusing when multiple statements: `if ((x = 10, y = 20) > 15)`
>> >> >>
>> >> >> Looks like an error: `if( x = 5 )` versus `if( x == 5)`, did the
>> >> >> programmer forget the `=`?
>> >> >>
>> >> >> And if you introduce nesting initializations everywhere outside the
>> >> >> `if`, that's basically an invitation for readability nightmare.
>> >> >> `let`
>> >> >> and `const` anywhere introduce 2 conflicting best-practices:
>> >> >>
>> >> >> - Rule 1: declare your variables that are used exclusively within
>> >> >> `if`
>> >> >> blocks within the `if` parens
>> >> >>
>> >> >> - Rule 2: don't declare variables within another statement (so that
>> >> >> people will refrain from doing `foo( let x=10 )`
>> >> >>
>> >> >> Consider that, historically, other languages such as Perl allowed
>> >> >> `if(
>> >> >> (my $x = 1) > 0)` and `foo( my $x = 100)` and became the ugly child
>> >> >> of
>> >> >> power programming; whereas Golang, born much later, has limited
>> >> >> initializations to things such as `if( x:=1; x > 0)` and has kept
>> >> >> things quite minimalistic (and clear for the programmer).
>> >> >>
>> >> >> ```perl
>> >> >> # realworld example, hard to find variable declaration:
>> >> >>
>> >> >> $redis->subscribe( 'queue', my $callback = sub {
>> >> >>     ...
>> >> >> });
>> >> >> ```
>> >> >>
>> >> >>
>> >> >> On Fri, Mar 23, 2018 at 7:21 AM, Naveen Chawla
>> >> >> <[hidden email]>
>> >> >> wrote:
>> >> >> > I'm still not seeing a compelling case for not allowing `const` /
>> >> >> > `let`
>> >> >> > declarations to be evaluated as expressions. Or I've missed it.
>> >> >> >
>> >> >> > As was noted,
>> >> >> >
>> >> >> > `if(x = 5)` is already allowed.
>> >> >> >
>> >> >> > Is `if(const x = 5)` really that much of a stretch?
>> >> >> >
>> >> >> > To answer a concern about a function call like `myFunction(const x
>> >> >> > =
>> >> >> > 7)`, of
>> >> >> > course the scope of `x` would be where it is declared. It can't be
>> >> >> > anywhere
>> >> >> > else (like inside myFunction or something).
>> >> >> >
>> >> >> > On Thu, 22 Mar 2018 at 22:53 Isiah Meadows
>> >> >> > <[hidden email]>
>> >> >> > wrote:
>> >> >> >>
>> >> >> >> Probably true, more so than the `if (var ...)`/etc. (which can't
>> >> >> >> be
>> >> >> >> as
>> >> >> >> easily desugared). My `else` variant desugars more to something
>> >> >> >> that
>> >> >> >> is also easily simulated, and it's a less common case:
>> >> >> >>
>> >> >> >> ```js
>> >> >> >> let foo = bar else return baz;
>> >> >> >>
>> >> >> >> // Desugared
>> >> >> >> let _tmp = bar;
>> >> >> >> if (tmp == null) return baz;
>> >> >> >> let foo = _tmp;
>> >> >> >> ```
>> >> >> >>
>> >> >> >> In this case, there's also the question of whether to require a
>> >> >> >> `return` in all code paths, which probably makes this a bit more
>> >> >> >> complicated than what would be worth for such a simple language
>> >> >> >> feature.
>> >> >> >> -----
>> >> >> >>
>> >> >> >> Isiah Meadows
>> >> >> >> [hidden email]
>> >> >> >>
>> >> >> >> Looking for web consulting? Or a new website?
>> >> >> >> Send me an email and we can get started.
>> >> >> >> www.isiahmeadows.com
>> >> >> >>
>> >> >> >>
>> >> >> >> On Thu, Mar 22, 2018 at 12:23 PM, Michael Luder-Rosefield
>> >> >> >> <[hidden email]> wrote:
>> >> >> >> > That strikes me as territory the 'do expression' proposal
>> >> >> >> > https://github.com/tc39/proposal-do-expressions is more fitted
>> >> >> >> > for:
>> >> >> >> >
>> >> >> >> >     const x = do { if (c) expr; else { ... } };
>> >> >> >> >
>> >> >> >> > What I'd like for this proposal is something that works
>> >> >> >> > consistently
>> >> >> >> > and
>> >> >> >> > obviously for all blocks with a parenthesised element to them.
>> >> >> >> > When
>> >> >> >> > they're
>> >> >> >> > formally separated by semi-colons, as in `for (a;b;c)`, each of
>> >> >> >> > `a,b,c`
>> >> >> >> > acts
>> >> >> >> > as an expression. Why not allow any of those expressions to be
>> >> >> >> > replaced
>> >> >> >> > by a
>> >> >> >> > statement block that acts like a do expression, each of which's
>> >> >> >> > scope
>> >> >> >> > is
>> >> >> >> > nested under the previous one and are available to the
>> >> >> >> > following
>> >> >> >> > block?
>> >> >> >> >
>> >> >> >> > That didn't come out very clearly, so let's try with an
>> >> >> >> > example:
>> >> >> >> >
>> >> >> >> >   for ({
>> >> >> >> >       let x = 1, y = 2;
>> >> >> >> >       console.log("I'll be printed every loop!");
>> >> >> >> >     }; {
>> >> >> >> >       let s = 'some string';
>> >> >> >> >       if (y%7 === 0) x === y;
>> >> >> >> >       else x < 1000;
>> >> >> >> >     }; {
>> >> >> >> >       let s = 'some other string';
>> >> >> >> >       x+=1;
>> >> >> >> >       if (y%3 === 0) y += 2;
>> >> >> >> >       else y += 1;
>> >> >> >> >     }) {
>> >> >> >> >       // whatever code here
>> >> >> >> >       // local scope hierarchy is
>> >> >> >> >       //   {
>> >> >> >> >       //     x,
>> >> >> >> >       //    y,
>> >> >> >> >       //    __SCOPE__: {
>> >> >> >> >       //      s: 'some string',
>> >> >> >> >       //      __SCOPE__: {
>> >> >> >> >       //        s: 'some other string'
>> >> >> >> >       //      }
>> >> >> >> >       //    }
>> >> >> >> >       //  }
>> >> >> >> >     }
>> >> >> >> >
>> >> >> >> > I'm just using some random logic in the blocks to illustrate
>> >> >> >> > the
>> >> >> >> > point:
>> >> >> >> > all
>> >> >> >> > the variables declared in the blocks are accessible in the for
>> >> >> >> > block,
>> >> >> >> > but
>> >> >> >> > the 'some string' `s` is masked by the 'some other string' `s`
>> >> >> >> > in
>> >> >> >> > the
>> >> >> >> > child
>> >> >> >> > scope. The termination condition in the second block can vary
>> >> >> >> > each
>> >> >> >> > loop,
>> >> >> >> > as
>> >> >> >> > can the iteration operation in the last block, and is simply
>> >> >> >> > the
>> >> >> >> > last
>> >> >> >> > value
>> >> >> >> > in the block as-per do expressions.
>> >> >> >> >
>> >> >> >> > On Thu, 22 Mar 2018 at 15:44 Mike Samuel <[hidden email]>
>> >> >> >> > wrote:
>> >> >> >> >>
>> >> >> >> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows
>> >> >> >> >> <[hidden email]>
>> >> >> >> >> wrote:
>> >> >> >> >>>
>> >> >> >> >>>
>> >> >> >> >>> I do have one other related thing I'd like to see: add a `let
>> >> >> >> >>> foo =
>> >> >> >> >>> expr() else { ... }` variant, with a line terminator
>> >> >> >> >>> restriction
>> >> >> >> >>> before the `else` so it can't be confused with an `else`
>> >> >> >> >>> within
>> >> >> >> >>> an
>> >> >> >> >>> `if`.
>> >> >> >> >>
>> >> >> >> >>
>> >> >> >> >> Making it a restricted production would solve the grammatical
>> >> >> >> >> ambiguity
>> >> >> >> >> for existing code, but maybe in an errorprone way for future
>> >> >> >> >> code:
>> >> >> >> >>
>> >> >> >> >>     if (c) let foo = expr() else { ... } // else attaches to
>> >> >> >> >> let
>> >> >> >> >>     if (c) let foo = expr(); else { ... } // else attaches to
>> >> >> >> >> if
>> >> >> >> >>
>> >> >> >> >>
>> >> >> >> >> Would the semantics differ from
>> >> >> >> >>
>> >> >> >> >>    let foo = expr() || ({} => { ... })()
>> >> >> >> >>
>> >> >> >> >> ?
>> >> >> >> >>
>> >> >> >> >>
>> >> >> >> >>
>> >> >> >> >>
>> >> >> >> >>>
>> >> >> >> >>>
>> >> >> >> >>> -----
>> >> >> >> >>>
>> >> >> >> >>> Isiah Meadows
>> >> >> >> >>> [hidden email]
>> >> >> >> >>>
>> >> >> >> >>> Looking for web consulting? Or a new website?
>> >> >> >> >>> Send me an email and we can get started.
>> >> >> >> >>> www.isiahmeadows.com
>> >> >> >> >>>
>> >> >> >> >>>
>> >> >> >> >>> On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo
>> >> >> >> >>> <[hidden email]>
>> >> >> >> >>> wrote:
>> >> >> >> >>> > Not just let-scopes, but the introduction of `async/await`
>> >> >> >> >>> > also
>> >> >> >> >>> > welcomes the introduction of if-scoped variables.
>> >> >> >> >>> >
>> >> >> >> >>> >     if (const data = await collection.find({}).toArray();
>> >> >> >> >>> > data.length >
>> >> >> >> >>> > 10)
>> >> >> >> >>> > {
>> >> >> >> >>> >         console.log(data);
>> >> >> >> >>> >     } else if (data.length > 0) {
>> >> >> >> >>> >         console.log(data);
>> >> >> >> >>> >     } else {
>> >> >> >> >>> >         console.log(data);
>> >> >> >> >>> >     }
>> >> >> >> >>> >
>> >> >> >> >>> > And, as mentioned by @jerry, this can be extended to
>> >> >> >> >>> > `switch`
>> >> >> >> >>> > and
>> >> >> >> >>> > `while`. Golang has `switch(;)` initialization too afaik.
>> >> >> >> >>> >
>> >> >> >> >>> >     switch( const today = new Date(); today.getDay() ) {
>> >> >> >> >>> >          case 0:
>> >> >> >> >>> >             console.log( "Don't work on %s",
>> >> >> >> >>> > today.toString()
>> >> >> >> >>> > );
>> >> >> >> >>> >             break;
>> >> >> >> >>> >     }
>> >> >> >> >>> >
>> >> >> >> >>> > `while` would be a bit unnecessary, due to the fact that it
>> >> >> >> >>> > can
>> >> >> >> >>> > be
>> >> >> >> >>> > replicated with `for( <assign>; <expression>; )`, but could
>> >> >> >> >>> > be
>> >> >> >> >>> > available for consistency with `if` and `switch`.
>> >> >> >> >>> >
>> >> >> >> >>> > El mié., 21 mar. 2018 19:47, Mike Samuel
>> >> >> >> >>> > <[hidden email]>
>> >> >> >> >>> > escribió:
>> >> >> >> >>> >>
>> >> >> >> >>> >>
>> >> >> >> >>> >>
>> >> >> >> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton
>> >> >> >> >>> >> <[hidden email]>
>> >> >> >> >>> >> wrote:
>> >> >> >> >>> >>>
>> >> >> >> >>> >>> Because block-level scoping is a very good way to avoid
>> >> >> >> >>> >>> certain
>> >> >> >> >>> >>> bugs
>> >> >> >> >>> >>> and
>> >> >> >> >>> >>> is easier to reason about. Especially when considering
>> >> >> >> >>> >>> project
>> >> >> >> >>> >>> successors.
>> >> >> >> >>> >>
>> >> >> >> >>> >>
>> >> >> >> >>> >> +1.  function-scoped variables in loop bodies caused tons
>> >> >> >> >>> >> of
>> >> >> >> >>> >> bugs
>> >> >> >> >>> >> before
>> >> >> >> >>> >> let-scoped variables and were a main motivating case.
>> >> >> >> >>> >>
>> >> >> >> >>> >> var i;
>> >> >> >> >>> >> for (i = 0; i < arr.length; ++i) {
>> >> >> >> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >> >> >> >>> >> }
>> >> >> >> >>> >>
>> >> >> >> >>> >> vs
>> >> >> >> >>> >>
>> >> >> >> >>> >> for (let i = 0; i < arr.length; ++i) {
>> >> >> >> >>> >>   f(function () { /* Do something with */ arr[i]; });
>> >> >> >> >>> >> }
>> >> >> >> >>> >>
>> >> >> >> >>> >> Yes, linters got pretty good at finding uses of
>> >> >> >> >>> >> closed-over
>> >> >> >> >>> >> variables
>> >> >> >> >>> >> modified in a loop, but the workarounds were not ideal.
>> >> >> >> >>> >>
>> >> >> >> >>> >> var i;
>> >> >> >> >>> >> for (i = 0; i < arr.length; ++i) {
>> >> >> >> >>> >>   f(function (i) { return function () { /* Do something
>> >> >> >> >>> >> with
>> >> >> >> >>> >> */
>> >> >> >> >>> >> arr[i]; }
>> >> >> >> >>> >> }(i));
>> >> >> >> >>> >> }
>> >> >> >> >>> >>
>> >> >> >> >>> >> Block scoping is just better for code that uses loops,
>> >> >> >> >>> >> variables,
>> >> >> >> >>> >> and
>> >> >> >> >>> >> function expressions.
>> >> >> >> >>> >>
>> >> >> >> >>> >> _______________________________________________
>> >> >> >> >>> >> 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
>> >> >> >> >>> >
>> >> >> >> >>
>> >> >> >> >> _______________________________________________
>> >> >> >> >> 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
>> >> >> >
>> >> >> >
>> >> >> > _______________________________________________
>> >> >> > 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: Proposal: if variable initialization

Isiah Meadows-2
In reply to this post by Isiah Meadows-2
As a counterpoint, Rust and Swift are the opposite: it's only defined
in the consequent branch, not the alternate. So it could go both ways.

But if a value is useful in both branches, I'd prefer to just define
the variable in a separate statement, to clarify that it's useful in
both branches (explicit > implicit). To take your example, I'd prefer
instead to do this:

```js
let foo = getFoo()

if (foo.isReady()) {
    foo.start()
} else {
    foo.wait()
}
```
-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Sun, Mar 25, 2018 at 5:42 AM, Maël Nison <[hidden email]> wrote:

> C++ defines it as being available in both branches, I think we try to share
> the same behavior. Keep in mind that it will useful when the check is on
> something different than existence :
>
> if (let foo = getFoo() ; foo.isReady())
>     foo.start();
> else
>     foo.wait();
>
> On Wed, Mar 21, 2018, 10:27 PM Isiah Meadows <[hidden email]> wrote:
>>
>> My implication was that it'd only be available in the `if` (if
>> declared with `let`/`const`).
>> -----
>>
>> Isiah Meadows
>> [hidden email]
>>
>> Looking for web consulting? Or a new website?
>> Send me an email and we can get started.
>> www.isiahmeadows.com
>>
>>
>> On Wed, Mar 21, 2018 at 6:25 PM, Sebastian Malton <[hidden email]>
>> wrote:
>> > Sorry if I missed a message but would such an initialization be only
>> > available in the first `if` block or also in the subsequent `else if` and
>> > `else` blocks?
>> >
>> > Sebastian Malton
>> >
>> >
>> >   Original Message
>> > From: [hidden email]
>> > Sent: March 21, 2018 6:18 PM
>> > To: [hidden email]
>> > Cc: [hidden email]; [hidden email]
>> > Subject: Re: Proposal: if variable initialization
>> >
>> > I'm personally very much *for* this `if (var ...; cond) { ... }`
>> > syntax. I couldn't tell you how many times I would've liked something
>> > to that effect, since that's probably one of my biggest areas of
>> > boilerplate.
>> >
>> > I would also be in favor of `if (var ...) { ... }` as a shorthand that
>> > guards `!= null` the expression result (pre-match), since that's about
>> > 90% of my use cases for it. There *is* a potential area of ambiguity
>> > in sloppy for `if ( let [ x ] = y )`, since that would be currently
>> > parsed as `var tmp = y; let[x] = tmp; if (tmp) { ... }`, but I doubt
>> > breaking that would be of much web compat risk. (A similar ambiguity
>> > existed with `for (let [`, but that break didn't cause many issues.)
>> > -----
>> >
>> > Isiah Meadows
>> > [hidden email]
>> >
>> > Looking for web consulting? Or a new website?
>> > Send me an email and we can get started.
>> > www.isiahmeadows.com
>> >
>> >
>> > On Wed, Mar 21, 2018 at 2:47 PM, Mike Samuel <[hidden email]>
>> > wrote:
>> >>
>> >>
>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton
>> >> <[hidden email]>
>> >> wrote:
>> >>>
>> >>> Because block-level scoping is a very good way to avoid certain bugs
>> >>> and
>> >>> is easier to reason about. Especially when considering project
>> >>> successors.
>> >>
>> >>
>> >> +1.  function-scoped variables in loop bodies caused tons of bugs
>> >> before
>> >> let-scoped variables and were a main motivating case.
>> >>
>> >> var i;
>> >> for (i = 0; i < arr.length; ++i) {
>> >>   f(function () { /* Do something with */ arr[i]; });
>> >> }
>> >>
>> >> vs
>> >>
>> >> for (let i = 0; i < arr.length; ++i) {
>> >>   f(function () { /* Do something with */ arr[i]; });
>> >> }
>> >>
>> >> Yes, linters got pretty good at finding uses of closed-over variables
>> >> modified in a loop, but the workarounds were not ideal.
>> >>
>> >> var i;
>> >> for (i = 0; i < arr.length; ++i) {
>> >>   f(function (i) { return function () { /* Do something with */ arr[i];
>> >> }
>> >> }(i));
>> >> }
>> >>
>> >> Block scoping is just better for code that uses loops, variables, and
>> >> function expressions.
>> >>
>> >>
>> >> _______________________________________________
>> >> 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
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
123