Proposal: if variable initialization
Is the use case only ever to capture the thing that serves as the conditional?
If so, would perhaps something like if.value
work better? Since it's a
keyword, it could be made to only work in the if
block, and you wouldn't
need any of that odd multi-statement stuff in the conditional parens.
Is the use case only ever to capture the thing that serves as the conditional? If so, would perhaps something like `if.value` work better? Since it's a keyword, it could be made to only work in the `if` block, and you wouldn't need any of that odd multi-statement stuff in the conditional parens. On Tue, Mar 20, 2018 at 12:57 PM, Rodrigo <rodrigolive at gmail.com> wrote: > Proposal: inline let/const statements to declare and initialize > variables within if statements, so that temporary variables exist only > within the if/else block scope. > > Reason: limits variable scope to the block where really needed, in > similar fashion to variables defined in for(;;) statements. This > improves readability while reducing unnecessary variables roaming > outside their needed block. > > The syntax would be very similar to the for(;;) assignment/test pair: > > if (let x = 100; x > 50) { > console.log(x); // 100 > } > console.log(x); // ReferenceError > > // same for const > if( const x = foo(); typeof x === 'object' ) { > //... > } > > // the variable is available within any else block > // after its declaration > if (let x = foo(); x < 50) { > console.log(x); // y is not available here > } else if (let y = bar(); y > 0) { > console.log(x, y); > } else { > console.log(x, y); > } > > Right now there isn't a way to limit a variable to the if block: > > let x = 100; > if (x > 50) { > console.log(x); > } > // x is in scope, but may not be needed beyond the if statement > console.log(x); > > // or a non-strict assignment, which also "leaks" scope > if( (x = 100) > 50 ) { > // ... > } > > There are many "workarounds" available, here's a few: > > // workaround 1: can be remedied with a scope block > // but it's asymmetrical and non-idiomatic > { > let x = 100; > if (x > 50) { > console.log(x); > } > } > > // workaround 2: with a for statement > // but this is non-idiomatic, hard to read and error-prone > for (let x = 100; x > 50;) { > console.log(x); > break; > } > > If-initialization is available in many languages (Go, Perl and Ruby > come to mind) and are considered best practice in each one of them: > > // Golang - x is defined, assigned and conditionally tested > if x := 100; x > 50 { > // x is in scope here > } else { > // and in here > } > // x is not available here > > ###### Perl > if( my $x = 100 ) { > print $x; > } > print $x; # an error > > if ( ( my $x = myfoo() ) > 50 ) { # also ok in Perl > print $x; > } > > ###### Ruby > if ( x = 100 ) # parens required per style guide > puts(x) > end > puts(x) # unfortunately Ruby does not limit scope to if, so x "leaks" > > I think this would be a great and important addition to the language. > > -Rodrigo > > PS: Just for the sake of comparison, Perl-style if-assignments could also > be an > option, albeit a very bad one IMO: > > if( ( let x = 100 ) > 50 ) { > } > > A Perl-style, value-returning let/const has readability issues, opens > quite a few fronts and sort of implies that let/const can return > values anywhere in the code outside if/else. On the other hand it > would fit with the currently if assignment if( x = y ). Definitely not > recommended. > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180320/0151349c/attachment.html>
What would if.value
look like in an example?
Wouldn't it be possible to have something like if(const x = getX() && const y = getY())
to capture more than just the conditional if required?
I'm guessing that would probably break something somewhere, but I'm not
sure what.
What would `if.value` look like in an example? Wouldn't it be possible to have something like `if(const x = getX() && const y = getY())` to capture more than just the conditional if required? I'm guessing that would probably break something somewhere, but I'm not sure what. On Wed, 21 Mar 2018 at 04:35 Jordan Harband <ljharb at gmail.com> wrote: > Is the use case only ever to capture the thing that serves as the > conditional? > > If so, would perhaps something like `if.value` work better? Since it's a > keyword, it could be made to only work in the `if` block, and you wouldn't > need any of that odd multi-statement stuff in the conditional parens. > > On Tue, Mar 20, 2018 at 12:57 PM, Rodrigo <rodrigolive at gmail.com> wrote: > >> Proposal: inline let/const statements to declare and initialize >> variables within if statements, so that temporary variables exist only >> within the if/else block scope. >> >> Reason: limits variable scope to the block where really needed, in >> similar fashion to variables defined in for(;;) statements. This >> improves readability while reducing unnecessary variables roaming >> outside their needed block. >> >> The syntax would be very similar to the for(;;) assignment/test pair: >> >> if (let x = 100; x > 50) { >> console.log(x); // 100 >> } >> console.log(x); // ReferenceError >> >> // same for const >> if( const x = foo(); typeof x === 'object' ) { >> //... >> } >> >> // the variable is available within any else block >> // after its declaration >> if (let x = foo(); x < 50) { >> console.log(x); // y is not available here >> } else if (let y = bar(); y > 0) { >> console.log(x, y); >> } else { >> console.log(x, y); >> } >> >> Right now there isn't a way to limit a variable to the if block: >> >> let x = 100; >> if (x > 50) { >> console.log(x); >> } >> // x is in scope, but may not be needed beyond the if statement >> console.log(x); >> >> // or a non-strict assignment, which also "leaks" scope >> if( (x = 100) > 50 ) { >> // ... >> } >> >> There are many "workarounds" available, here's a few: >> >> // workaround 1: can be remedied with a scope block >> // but it's asymmetrical and non-idiomatic >> { >> let x = 100; >> if (x > 50) { >> console.log(x); >> } >> } >> >> // workaround 2: with a for statement >> // but this is non-idiomatic, hard to read and error-prone >> for (let x = 100; x > 50;) { >> console.log(x); >> break; >> } >> >> If-initialization is available in many languages (Go, Perl and Ruby >> come to mind) and are considered best practice in each one of them: >> >> // Golang - x is defined, assigned and conditionally tested >> if x := 100; x > 50 { >> // x is in scope here >> } else { >> // and in here >> } >> // x is not available here >> >> ###### Perl >> if( my $x = 100 ) { >> print $x; >> } >> print $x; # an error >> >> if ( ( my $x = myfoo() ) > 50 ) { # also ok in Perl >> print $x; >> } >> >> ###### Ruby >> if ( x = 100 ) # parens required per style guide >> puts(x) >> end >> puts(x) # unfortunately Ruby does not limit scope to if, so x "leaks" >> >> I think this would be a great and important addition to the language. >> >> -Rodrigo >> >> PS: Just for the sake of comparison, Perl-style if-assignments could also >> be an >> option, albeit a very bad one IMO: >> >> if( ( let x = 100 ) > 50 ) { >> } >> >> A Perl-style, value-returning let/const has readability issues, opens >> quite a few fronts and sort of implies that let/const can return >> values anywhere in the code outside if/else. On the other hand it >> would fit with the currently if assignment if( x = y ). Definitely not >> recommended. >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180321/05b9e1aa/attachment.html>
OK I neglected to read the original post fully. My last post example would
be based on allowing const
and let
declarations to expressions in of
themselves (in the case of multi variables, returning the last one). So let
me ask, what exactly would be the problem with this?
OK I neglected to read the original post fully. My last post example would be based on allowing `const` and `let` declarations to expressions in of themselves (in the case of multi variables, returning the last one). So let me ask, what exactly would be the problem with this? On Wed, 21 Mar 2018 at 12:20 Naveen Chawla <naveen.chwl at gmail.com> wrote: > What would `if.value` look like in an example? > > Wouldn't it be possible to have something like `if(const x = getX() && > const y = getY())` to capture more than just the conditional if required? > I'm guessing that would probably break something somewhere, but I'm not > sure what. > > On Wed, 21 Mar 2018 at 04:35 Jordan Harband <ljharb at gmail.com> wrote: > >> Is the use case only ever to capture the thing that serves as the >> conditional? >> >> If so, would perhaps something like `if.value` work better? Since it's a >> keyword, it could be made to only work in the `if` block, and you wouldn't >> need any of that odd multi-statement stuff in the conditional parens. >> >> On Tue, Mar 20, 2018 at 12:57 PM, Rodrigo <rodrigolive at gmail.com> wrote: >> >>> Proposal: inline let/const statements to declare and initialize >>> variables within if statements, so that temporary variables exist only >>> within the if/else block scope. >>> >>> Reason: limits variable scope to the block where really needed, in >>> similar fashion to variables defined in for(;;) statements. This >>> improves readability while reducing unnecessary variables roaming >>> outside their needed block. >>> >>> The syntax would be very similar to the for(;;) assignment/test pair: >>> >>> if (let x = 100; x > 50) { >>> console.log(x); // 100 >>> } >>> console.log(x); // ReferenceError >>> >>> // same for const >>> if( const x = foo(); typeof x === 'object' ) { >>> //... >>> } >>> >>> // the variable is available within any else block >>> // after its declaration >>> if (let x = foo(); x < 50) { >>> console.log(x); // y is not available here >>> } else if (let y = bar(); y > 0) { >>> console.log(x, y); >>> } else { >>> console.log(x, y); >>> } >>> >>> Right now there isn't a way to limit a variable to the if block: >>> >>> let x = 100; >>> if (x > 50) { >>> console.log(x); >>> } >>> // x is in scope, but may not be needed beyond the if statement >>> console.log(x); >>> >>> // or a non-strict assignment, which also "leaks" scope >>> if( (x = 100) > 50 ) { >>> // ... >>> } >>> >>> There are many "workarounds" available, here's a few: >>> >>> // workaround 1: can be remedied with a scope block >>> // but it's asymmetrical and non-idiomatic >>> { >>> let x = 100; >>> if (x > 50) { >>> console.log(x); >>> } >>> } >>> >>> // workaround 2: with a for statement >>> // but this is non-idiomatic, hard to read and error-prone >>> for (let x = 100; x > 50;) { >>> console.log(x); >>> break; >>> } >>> >>> If-initialization is available in many languages (Go, Perl and Ruby >>> come to mind) and are considered best practice in each one of them: >>> >>> // Golang - x is defined, assigned and conditionally tested >>> if x := 100; x > 50 { >>> // x is in scope here >>> } else { >>> // and in here >>> } >>> // x is not available here >>> >>> ###### Perl >>> if( my $x = 100 ) { >>> print $x; >>> } >>> print $x; # an error >>> >>> if ( ( my $x = myfoo() ) > 50 ) { # also ok in Perl >>> print $x; >>> } >>> >>> ###### Ruby >>> if ( x = 100 ) # parens required per style guide >>> puts(x) >>> end >>> puts(x) # unfortunately Ruby does not limit scope to if, so x "leaks" >>> >>> I think this would be a great and important addition to the language. >>> >>> -Rodrigo >>> >>> PS: Just for the sake of comparison, Perl-style if-assignments could >>> also be an >>> option, albeit a very bad one IMO: >>> >>> if( ( let x = 100 ) > 50 ) { >>> } >>> >>> A Perl-style, value-returning let/const has readability issues, opens >>> quite a few fronts and sort of implies that let/const can return >>> values anywhere in the code outside if/else. On the other hand it >>> would fit with the currently if assignment if( x = y ). Definitely not >>> recommended. >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180321/6082e6ba/attachment-0001.html>
Here are my gripes with let
and const
returning values:
-
declaration lists are hard to read:
if ((let x = 10, y = 20) > 15) { // true, but what's being compared here? 10 or 20? (answer: 20) }
Although right now this is allowed and the last element is compared:
if ((x = 10, y = 20) > 15) {
// result is true, 20 > 15
}
-
Destructuring assignments are also confusing, what's being compared here?
if(let [x,y] = [1,2]) { }
Again, this is allowed as of today:
if([x,y] = [1,2]) {
// true, as it returns [1,2]
}
-
Nesting
let/const
would be either expected everywhere (not only in theif
) or a possible side effect from the implementation. Similar to languages such as Perl.let x = foo(let y = 100, z = 200); // what's the scope of x and z?
This leads to hard to read and very confusing code golf.
That's why Golang went with something simple,
if([declaration];[conditional])
, and avoided confusion over :=
assignments returning values anywhere in the code. x:=( y:= 20 )
is
not allowed in Go.
It expands on the 45-year tried-and-true structure of for(;;)
to
create if(;)
and keep the ES language simple and clear expanding on
its own concept of for(;;)
.
Here are my gripes with `let` and `const` returning values: 1) declaration lists are hard to read: if ((let x = 10, y = 20) > 15) { // true, but what's being compared here? 10 or 20? (answer: 20) } Although right now this is allowed and the last element is compared: if ((x = 10, y = 20) > 15) { // result is true, 20 > 15 } 2) Destructuring assignments are also confusing, what's being compared here? if(let [x,y] = [1,2]) { } Again, this is allowed as of today: if([x,y] = [1,2]) { // true, as it returns [1,2] } 3) Nesting `let/const` would be either expected everywhere (not only in the `if`) or a possible side effect from the implementation. Similar to languages such as Perl. let x = foo(let y = 100, z = 200); // what's the scope of x and z? This leads to hard to read and very confusing code golf. That's why Golang went with something simple, `if([declaration];[conditional])`, and avoided confusion over `:=` assignments returning values anywhere in the code. `x:=( y:= 20 )` is not allowed in Go. It expands on the 45-year tried-and-true structure of `for(;;)` to create `if(;)` and keep the ES language simple and clear expanding on its own concept of `for(;;)`. On Wed, Mar 21, 2018 at 7:57 AM, Naveen Chawla <naveen.chwl at gmail.com> wrote: > OK I neglected to read the original post fully. My last post example would > be based on allowing `const` and `let` declarations to expressions in of > themselves (in the case of multi variables, returning the last one). So let > me ask, what exactly would be the problem with this? > > On Wed, 21 Mar 2018 at 12:20 Naveen Chawla <naveen.chwl at gmail.com> wrote: >> >> What would `if.value` look like in an example? >> >> Wouldn't it be possible to have something like `if(const x = getX() && >> const y = getY())` to capture more than just the conditional if required? >> I'm guessing that would probably break something somewhere, but I'm not sure >> what. >> >> On Wed, 21 Mar 2018 at 04:35 Jordan Harband <ljharb at gmail.com> wrote: >>> >>> Is the use case only ever to capture the thing that serves as the >>> conditional? >>> >>> If so, would perhaps something like `if.value` work better? Since it's a >>> keyword, it could be made to only work in the `if` block, and you wouldn't >>> need any of that odd multi-statement stuff in the conditional parens. >>> >>> On Tue, Mar 20, 2018 at 12:57 PM, Rodrigo <rodrigolive at gmail.com> wrote: >>>> >>>> Proposal: inline let/const statements to declare and initialize >>>> variables within if statements, so that temporary variables exist only >>>> within the if/else block scope. >>>> >>>> Reason: limits variable scope to the block where really needed, in >>>> similar fashion to variables defined in for(;;) statements. This >>>> improves readability while reducing unnecessary variables roaming >>>> outside their needed block. >>>> >>>> The syntax would be very similar to the for(;;) assignment/test pair: >>>> >>>> if (let x = 100; x > 50) { >>>> console.log(x); // 100 >>>> } >>>> console.log(x); // ReferenceError >>>> >>>> // same for const >>>> if( const x = foo(); typeof x === 'object' ) { >>>> //... >>>> } >>>> >>>> // the variable is available within any else block >>>> // after its declaration >>>> if (let x = foo(); x < 50) { >>>> console.log(x); // y is not available here >>>> } else if (let y = bar(); y > 0) { >>>> console.log(x, y); >>>> } else { >>>> console.log(x, y); >>>> } >>>> >>>> Right now there isn't a way to limit a variable to the if block: >>>> >>>> let x = 100; >>>> if (x > 50) { >>>> console.log(x); >>>> } >>>> // x is in scope, but may not be needed beyond the if statement >>>> console.log(x); >>>> >>>> // or a non-strict assignment, which also "leaks" scope >>>> if( (x = 100) > 50 ) { >>>> // ... >>>> } >>>> >>>> There are many "workarounds" available, here's a few: >>>> >>>> // workaround 1: can be remedied with a scope block >>>> // but it's asymmetrical and non-idiomatic >>>> { >>>> let x = 100; >>>> if (x > 50) { >>>> console.log(x); >>>> } >>>> } >>>> >>>> // workaround 2: with a for statement >>>> // but this is non-idiomatic, hard to read and error-prone >>>> for (let x = 100; x > 50;) { >>>> console.log(x); >>>> break; >>>> } >>>> >>>> If-initialization is available in many languages (Go, Perl and Ruby >>>> come to mind) and are considered best practice in each one of them: >>>> >>>> // Golang - x is defined, assigned and conditionally tested >>>> if x := 100; x > 50 { >>>> // x is in scope here >>>> } else { >>>> // and in here >>>> } >>>> // x is not available here >>>> >>>> ###### Perl >>>> if( my $x = 100 ) { >>>> print $x; >>>> } >>>> print $x; # an error >>>> >>>> if ( ( my $x = myfoo() ) > 50 ) { # also ok in Perl >>>> print $x; >>>> } >>>> >>>> ###### Ruby >>>> if ( x = 100 ) # parens required per style guide >>>> puts(x) >>>> end >>>> puts(x) # unfortunately Ruby does not limit scope to if, so x >>>> "leaks" >>>> >>>> I think this would be a great and important addition to the language. >>>> >>>> -Rodrigo >>>> >>>> PS: Just for the sake of comparison, Perl-style if-assignments could >>>> also be an >>>> option, albeit a very bad one IMO: >>>> >>>> if( ( let x = 100 ) > 50 ) { >>>> } >>>> >>>> A Perl-style, value-returning let/const has readability issues, opens >>>> quite a few fronts and sort of implies that let/const can return >>>> values anywhere in the code outside if/else. On the other hand it >>>> would fit with the currently if assignment if( x = y ). Definitely not >>>> recommended. >>>> _______________________________________________ >>>> es-discuss mailing list >>>> es-discuss at mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>> >>> >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss
if (someComplicatedCondition()) {
doSomeLogic();
doSomeOtherLogic(if.value, true);
}
``` if (someComplicatedCondition()) { doSomeLogic(); doSomeOtherLogic(if.value, true); } ``` On Wed, Mar 21, 2018 at 2:52 AM, Rodrigo <rodrigolive at gmail.com> wrote: > Here are my gripes with `let` and `const` returning values: > > 1) declaration lists are hard to read: > > if ((let x = 10, y = 20) > 15) { > // true, but what's being compared here? 10 or 20? (answer: 20) > } > > Although right now this is allowed and the last element is compared: > > if ((x = 10, y = 20) > 15) { > // result is true, 20 > 15 > } > > 2) Destructuring assignments are also confusing, what's being compared > here? > > if(let [x,y] = [1,2]) { > } > > Again, this is allowed as of today: > > if([x,y] = [1,2]) { > // true, as it returns [1,2] > } > > 3) Nesting `let/const` would be either expected everywhere (not only > in the `if`) or a possible side effect from the implementation. > Similar to languages such as Perl. > > let x = foo(let y = 100, z = 200); // what's the scope of x and z? > > This leads to hard to read and very confusing code golf. > > That's why Golang went with something simple, > `if([declaration];[conditional])`, and avoided confusion over `:=` > assignments returning values anywhere in the code. `x:=( y:= 20 )` is > not allowed in Go. > > It expands on the 45-year tried-and-true structure of `for(;;)` to > create `if(;)` and keep the ES language simple and clear expanding on > its own concept of `for(;;)`. > > On Wed, Mar 21, 2018 at 7:57 AM, Naveen Chawla <naveen.chwl at gmail.com> > wrote: > > OK I neglected to read the original post fully. My last post example > would > > be based on allowing `const` and `let` declarations to expressions in of > > themselves (in the case of multi variables, returning the last one). So > let > > me ask, what exactly would be the problem with this? > > > > On Wed, 21 Mar 2018 at 12:20 Naveen Chawla <naveen.chwl at gmail.com> > wrote: > >> > >> What would `if.value` look like in an example? > >> > >> Wouldn't it be possible to have something like `if(const x = getX() && > >> const y = getY())` to capture more than just the conditional if > required? > >> I'm guessing that would probably break something somewhere, but I'm not > sure > >> what. > >> > >> On Wed, 21 Mar 2018 at 04:35 Jordan Harband <ljharb at gmail.com> wrote: > >>> > >>> Is the use case only ever to capture the thing that serves as the > >>> conditional? > >>> > >>> If so, would perhaps something like `if.value` work better? Since it's > a > >>> keyword, it could be made to only work in the `if` block, and you > wouldn't > >>> need any of that odd multi-statement stuff in the conditional parens. > >>> > >>> On Tue, Mar 20, 2018 at 12:57 PM, Rodrigo <rodrigolive at gmail.com> > wrote: > >>>> > >>>> Proposal: inline let/const statements to declare and initialize > >>>> variables within if statements, so that temporary variables exist only > >>>> within the if/else block scope. > >>>> > >>>> Reason: limits variable scope to the block where really needed, in > >>>> similar fashion to variables defined in for(;;) statements. This > >>>> improves readability while reducing unnecessary variables roaming > >>>> outside their needed block. > >>>> > >>>> The syntax would be very similar to the for(;;) assignment/test pair: > >>>> > >>>> if (let x = 100; x > 50) { > >>>> console.log(x); // 100 > >>>> } > >>>> console.log(x); // ReferenceError > >>>> > >>>> // same for const > >>>> if( const x = foo(); typeof x === 'object' ) { > >>>> //... > >>>> } > >>>> > >>>> // the variable is available within any else block > >>>> // after its declaration > >>>> if (let x = foo(); x < 50) { > >>>> console.log(x); // y is not available here > >>>> } else if (let y = bar(); y > 0) { > >>>> console.log(x, y); > >>>> } else { > >>>> console.log(x, y); > >>>> } > >>>> > >>>> Right now there isn't a way to limit a variable to the if block: > >>>> > >>>> let x = 100; > >>>> if (x > 50) { > >>>> console.log(x); > >>>> } > >>>> // x is in scope, but may not be needed beyond the if statement > >>>> console.log(x); > >>>> > >>>> // or a non-strict assignment, which also "leaks" scope > >>>> if( (x = 100) > 50 ) { > >>>> // ... > >>>> } > >>>> > >>>> There are many "workarounds" available, here's a few: > >>>> > >>>> // workaround 1: can be remedied with a scope block > >>>> // but it's asymmetrical and non-idiomatic > >>>> { > >>>> let x = 100; > >>>> if (x > 50) { > >>>> console.log(x); > >>>> } > >>>> } > >>>> > >>>> // workaround 2: with a for statement > >>>> // but this is non-idiomatic, hard to read and error-prone > >>>> for (let x = 100; x > 50;) { > >>>> console.log(x); > >>>> break; > >>>> } > >>>> > >>>> If-initialization is available in many languages (Go, Perl and Ruby > >>>> come to mind) and are considered best practice in each one of them: > >>>> > >>>> // Golang - x is defined, assigned and conditionally tested > >>>> if x := 100; x > 50 { > >>>> // x is in scope here > >>>> } else { > >>>> // and in here > >>>> } > >>>> // x is not available here > >>>> > >>>> ###### Perl > >>>> if( my $x = 100 ) { > >>>> print $x; > >>>> } > >>>> print $x; # an error > >>>> > >>>> if ( ( my $x = myfoo() ) > 50 ) { # also ok in Perl > >>>> print $x; > >>>> } > >>>> > >>>> ###### Ruby > >>>> if ( x = 100 ) # parens required per style guide > >>>> puts(x) > >>>> end > >>>> puts(x) # unfortunately Ruby does not limit scope to if, so x > >>>> "leaks" > >>>> > >>>> I think this would be a great and important addition to the language. > >>>> > >>>> -Rodrigo > >>>> > >>>> PS: Just for the sake of comparison, Perl-style if-assignments could > >>>> also be an > >>>> option, albeit a very bad one IMO: > >>>> > >>>> if( ( let x = 100 ) > 50 ) { > >>>> } > >>>> > >>>> A Perl-style, value-returning let/const has readability issues, opens > >>>> quite a few fronts and sort of implies that let/const can return > >>>> values anywhere in the code outside if/else. On the other hand it > >>>> would fit with the currently if assignment if( x = y ). Definitely not > >>>> recommended. > >>>> _______________________________________________ > >>>> es-discuss mailing list > >>>> es-discuss at mozilla.org > >>>> https://mail.mozilla.org/listinfo/es-discuss > >>> > >>> > >>> _______________________________________________ > >>> es-discuss mailing list > >>> es-discuss at mozilla.org > >>> https://mail.mozilla.org/listinfo/es-discuss > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180321/05bbf8fd/attachment-0001.html>
this is why let and const should never have been introduced. if we had stuck with just var, none of these petty-arguments and bickering among team-members/shops on scoping-styles that ultimately have zero productivity or benefit to web-projects would be possible.
and there's nothing wrong with pre-declaring all variables at the top-level of a function (which is an es5 best-practice that’s still valid today), regardless whether some are only used in conditional-blocks or not, like this real-world example [1]:
local.validateBySwaggerSchema = function (options) {
/*
* this function will validate data against schema
* http://json-schema.org/draft-04/json-schema-validation.html#rfc.section.5
*/
var $ref,
circularList,
data,
dataReadonlyRemove2,
ii,
oneOf,
schema,
test,
tmp;
...
// dereference schema.$ref
$ref = schema && schema.$ref;
if (!$ref) {
break;
}
...
tmp = typeof data;
if (tmp === 'object' && Array.isArray(data)) {
tmp = 'array';
}
...
if (schema === local.swaggerSchemaJson.definitions.jsonReference) {
...
}
...
};
[1] kaizhu256/node-swgg/blob/2018.2.1/lib.swgg.js#L4076, kaizhu256/node-swgg/blob/2018.2.1/lib.swgg.js#L4076
this is why let and const should *never* have been introduced. if we had stuck with just var, none of these petty-arguments and bickering among team-members/shops on scoping-styles that ultimately have *zero* productivity or benefit to web-projects would be possible. and there's nothing wrong with pre-declaring all variables at the top-level of a function (which is an es5 best-practice that’s still valid today), regardless whether some are only used in conditional-blocks or not, like this real-world example [1]: ``` local.validateBySwaggerSchema = function (options) { /* * this function will validate data against schema * http://json-schema.org/draft-04/json-schema-validation.html#rfc.section.5 */ var $ref, circularList, data, dataReadonlyRemove2, ii, oneOf, schema, test, tmp; ... // dereference schema.$ref $ref = schema && schema.$ref; if (!$ref) { break; } ... tmp = typeof data; if (tmp === 'object' && Array.isArray(data)) { tmp = 'array'; } ... if (schema === local.swaggerSchemaJson.definitions.jsonReference) { ... } ... }; ``` [1] https://github.com/kaizhu256/node-swgg/blob/2018.2.1/lib.swgg.js#L4076 <https://github.com/kaizhu256/node-swgg/blob/2018.2.1/lib.swgg.js#L4076> -kai > On Mar 21, 2018, at 7:15 PM, Jordan Harband <ljharb at gmail.com> wrote: > > ``` > if (someComplicatedCondition()) { > doSomeLogic(); > doSomeOtherLogic(if.value, true); > } > ``` > > On Wed, Mar 21, 2018 at 2:52 AM, Rodrigo <rodrigolive at gmail.com <mailto:rodrigolive at gmail.com>> wrote: > Here are my gripes with `let` and `const` returning values: > > 1) declaration lists are hard to read: > > if ((let x = 10, y = 20) > 15) { > // true, but what's being compared here? 10 or 20? (answer: 20) > } > > Although right now this is allowed and the last element is compared: > > if ((x = 10, y = 20) > 15) { > // result is true, 20 > 15 > } > > 2) Destructuring assignments are also confusing, what's being compared here? > > if(let [x,y] = [1,2]) { > } > > Again, this is allowed as of today: > > if([x,y] = [1,2]) { > // true, as it returns [1,2] > } > > 3) Nesting `let/const` would be either expected everywhere (not only > in the `if`) or a possible side effect from the implementation. > Similar to languages such as Perl. > > let x = foo(let y = 100, z = 200); // what's the scope of x and z? > > This leads to hard to read and very confusing code golf. > > That's why Golang went with something simple, > `if([declaration];[conditional])`, and avoided confusion over `:=` > assignments returning values anywhere in the code. `x:=( y:= 20 )` is > not allowed in Go. > > It expands on the 45-year tried-and-true structure of `for(;;)` to > create `if(;)` and keep the ES language simple and clear expanding on > its own concept of `for(;;)`. > > On Wed, Mar 21, 2018 at 7:57 AM, Naveen Chawla <naveen.chwl at gmail.com <mailto:naveen.chwl at gmail.com>> wrote: > > OK I neglected to read the original post fully. My last post example would > > be based on allowing `const` and `let` declarations to expressions in of > > themselves (in the case of multi variables, returning the last one). So let > > me ask, what exactly would be the problem with this? > > > > On Wed, 21 Mar 2018 at 12:20 Naveen Chawla <naveen.chwl at gmail.com <mailto:naveen.chwl at gmail.com>> wrote: > >> > >> What would `if.value` look like in an example? > >> > >> Wouldn't it be possible to have something like `if(const x = getX() && > >> const y = getY())` to capture more than just the conditional if required? > >> I'm guessing that would probably break something somewhere, but I'm not sure > >> what. > >> > >> On Wed, 21 Mar 2018 at 04:35 Jordan Harband <ljharb at gmail.com <mailto:ljharb at gmail.com>> wrote: > >>> > >>> Is the use case only ever to capture the thing that serves as the > >>> conditional? > >>> > >>> If so, would perhaps something like `if.value` work better? Since it's a > >>> keyword, it could be made to only work in the `if` block, and you wouldn't > >>> need any of that odd multi-statement stuff in the conditional parens. > >>> > >>> On Tue, Mar 20, 2018 at 12:57 PM, Rodrigo <rodrigolive at gmail.com <mailto:rodrigolive at gmail.com>> wrote: > >>>> > >>>> Proposal: inline let/const statements to declare and initialize > >>>> variables within if statements, so that temporary variables exist only > >>>> within the if/else block scope. > >>>> > >>>> Reason: limits variable scope to the block where really needed, in > >>>> similar fashion to variables defined in for(;;) statements. This > >>>> improves readability while reducing unnecessary variables roaming > >>>> outside their needed block. > >>>> > >>>> The syntax would be very similar to the for(;;) assignment/test pair: > >>>> > >>>> if (let x = 100; x > 50) { > >>>> console.log(x); // 100 > >>>> } > >>>> console.log(x); // ReferenceError > >>>> > >>>> // same for const > >>>> if( const x = foo(); typeof x === 'object' ) { > >>>> //... > >>>> } > >>>> > >>>> // the variable is available within any else block > >>>> // after its declaration > >>>> if (let x = foo(); x < 50) { > >>>> console.log(x); // y is not available here > >>>> } else if (let y = bar(); y > 0) { > >>>> console.log(x, y); > >>>> } else { > >>>> console.log(x, y); > >>>> } > >>>> > >>>> Right now there isn't a way to limit a variable to the if block: > >>>> > >>>> let x = 100; > >>>> if (x > 50) { > >>>> console.log(x); > >>>> } > >>>> // x is in scope, but may not be needed beyond the if statement > >>>> console.log(x); > >>>> > >>>> // or a non-strict assignment, which also "leaks" scope > >>>> if( (x = 100) > 50 ) { > >>>> // ... > >>>> } > >>>> > >>>> There are many "workarounds" available, here's a few: > >>>> > >>>> // workaround 1: can be remedied with a scope block > >>>> // but it's asymmetrical and non-idiomatic > >>>> { > >>>> let x = 100; > >>>> if (x > 50) { > >>>> console.log(x); > >>>> } > >>>> } > >>>> > >>>> // workaround 2: with a for statement > >>>> // but this is non-idiomatic, hard to read and error-prone > >>>> for (let x = 100; x > 50;) { > >>>> console.log(x); > >>>> break; > >>>> } > >>>> > >>>> If-initialization is available in many languages (Go, Perl and Ruby > >>>> come to mind) and are considered best practice in each one of them: > >>>> > >>>> // Golang - x is defined, assigned and conditionally tested > >>>> if x := 100; x > 50 { > >>>> // x is in scope here > >>>> } else { > >>>> // and in here > >>>> } > >>>> // x is not available here > >>>> > >>>> ###### Perl > >>>> if( my $x = 100 ) { > >>>> print $x; > >>>> } > >>>> print $x; # an error > >>>> > >>>> if ( ( my $x = myfoo() ) > 50 ) { # also ok in Perl > >>>> print $x; > >>>> } > >>>> > >>>> ###### Ruby > >>>> if ( x = 100 ) # parens required per style guide > >>>> puts(x) > >>>> end > >>>> puts(x) # unfortunately Ruby does not limit scope to if, so x > >>>> "leaks" > >>>> > >>>> I think this would be a great and important addition to the language. > >>>> > >>>> -Rodrigo > >>>> > >>>> PS: Just for the sake of comparison, Perl-style if-assignments could > >>>> also be an > >>>> option, albeit a very bad one IMO: > >>>> > >>>> if( ( let x = 100 ) > 50 ) { > >>>> } > >>>> > >>>> A Perl-style, value-returning let/const has readability issues, opens > >>>> quite a few fronts and sort of implies that let/const can return > >>>> values anywhere in the code outside if/else. On the other hand it > >>>> would fit with the currently if assignment if( x = y ). Definitely not > >>>> recommended. > >>>> _______________________________________________ > >>>> es-discuss mailing list > >>>> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> > >>>> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> > >>> > >>> > >>> _______________________________________________ > >>> es-discuss mailing list > >>> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> > >>> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> > https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180321/719bc166/attachment-0001.html>
Is this sarcastic?
Is this sarcastic? On 21 Mar 2018 12:58, "kai zhu" <kaizhu256 at gmail.com> wrote: > this is why let and const should *never* have been introduced. if we had > stuck with just var, none of these petty-arguments and bickering among > team-members/shops on scoping-styles that ultimately have *zero* > productivity or benefit to web-projects would be possible. > > and there's nothing wrong with pre-declaring all variables at the > top-level of a function (which is an es5 best-practice that’s still valid > today), regardless whether some are only used in conditional-blocks or not, > like this real-world example [1]: > > ``` > local.validateBySwaggerSchema = function (options) { > /* > * this function will validate data against schema > * http://json-schema.org/draft-04/json-schema-validation. > html#rfc.section.5 > */ > var $ref, > circularList, > data, > dataReadonlyRemove2, > ii, > oneOf, > schema, > test, > tmp; > ... > // dereference schema.$ref > $ref = schema && schema.$ref; > if (!$ref) { > break; > } > ... > tmp = typeof data; > if (tmp === 'object' && Array.isArray(data)) { > tmp = 'array'; > } > ... > if (schema === local.swaggerSchemaJson.definitions.jsonReference) { > ... > } > ... > }; > ``` > > [1] https://github.com/kaizhu256/node-swgg/blob/2018.2.1/lib.swgg.js#L4076 > > -kai > > On Mar 21, 2018, at 7:15 PM, Jordan Harband <ljharb at gmail.com> wrote: > > ``` > if (someComplicatedCondition()) { > doSomeLogic(); > doSomeOtherLogic(if.value, true); > } > ``` > > On Wed, Mar 21, 2018 at 2:52 AM, Rodrigo <rodrigolive at gmail.com> wrote: > >> Here are my gripes with `let` and `const` returning values: >> >> 1) declaration lists are hard to read: >> >> if ((let x = 10, y = 20) > 15) { >> // true, but what's being compared here? 10 or 20? (answer: 20) >> } >> >> Although right now this is allowed and the last element is compared: >> >> if ((x = 10, y = 20) > 15) { >> // result is true, 20 > 15 >> } >> >> 2) Destructuring assignments are also confusing, what's being compared >> here? >> >> if(let [x,y] = [1,2]) { >> } >> >> Again, this is allowed as of today: >> >> if([x,y] = [1,2]) { >> // true, as it returns [1,2] >> } >> >> 3) Nesting `let/const` would be either expected everywhere (not only >> in the `if`) or a possible side effect from the implementation. >> Similar to languages such as Perl. >> >> let x = foo(let y = 100, z = 200); // what's the scope of x and z? >> >> This leads to hard to read and very confusing code golf. >> >> That's why Golang went with something simple, >> `if([declaration];[conditional])`, and avoided confusion over `:=` >> assignments returning values anywhere in the code. `x:=( y:= 20 )` is >> not allowed in Go. >> >> It expands on the 45-year tried-and-true structure of `for(;;)` to >> create `if(;)` and keep the ES language simple and clear expanding on >> its own concept of `for(;;)`. >> >> On Wed, Mar 21, 2018 at 7:57 AM, Naveen Chawla <naveen.chwl at gmail.com> >> wrote: >> > OK I neglected to read the original post fully. My last post example >> would >> > be based on allowing `const` and `let` declarations to expressions in of >> > themselves (in the case of multi variables, returning the last one). So >> let >> > me ask, what exactly would be the problem with this? >> > >> > On Wed, 21 Mar 2018 at 12:20 Naveen Chawla <naveen.chwl at gmail.com> >> wrote: >> >> >> >> What would `if.value` look like in an example? >> >> >> >> Wouldn't it be possible to have something like `if(const x = getX() && >> >> const y = getY())` to capture more than just the conditional if >> required? >> >> I'm guessing that would probably break something somewhere, but I'm >> not sure >> >> what. >> >> >> >> On Wed, 21 Mar 2018 at 04:35 Jordan Harband <ljharb at gmail.com> wrote: >> >>> >> >>> Is the use case only ever to capture the thing that serves as the >> >>> conditional? >> >>> >> >>> If so, would perhaps something like `if.value` work better? Since >> it's a >> >>> keyword, it could be made to only work in the `if` block, and you >> wouldn't >> >>> need any of that odd multi-statement stuff in the conditional parens. >> >>> >> >>> On Tue, Mar 20, 2018 at 12:57 PM, Rodrigo <rodrigolive at gmail.com> >> wrote: >> >>>> >> >>>> Proposal: inline let/const statements to declare and initialize >> >>>> variables within if statements, so that temporary variables exist >> only >> >>>> within the if/else block scope. >> >>>> >> >>>> Reason: limits variable scope to the block where really needed, in >> >>>> similar fashion to variables defined in for(;;) statements. This >> >>>> improves readability while reducing unnecessary variables roaming >> >>>> outside their needed block. >> >>>> >> >>>> The syntax would be very similar to the for(;;) assignment/test pair: >> >>>> >> >>>> if (let x = 100; x > 50) { >> >>>> console.log(x); // 100 >> >>>> } >> >>>> console.log(x); // ReferenceError >> >>>> >> >>>> // same for const >> >>>> if( const x = foo(); typeof x === 'object' ) { >> >>>> //... >> >>>> } >> >>>> >> >>>> // the variable is available within any else block >> >>>> // after its declaration >> >>>> if (let x = foo(); x < 50) { >> >>>> console.log(x); // y is not available here >> >>>> } else if (let y = bar(); y > 0) { >> >>>> console.log(x, y); >> >>>> } else { >> >>>> console.log(x, y); >> >>>> } >> >>>> >> >>>> Right now there isn't a way to limit a variable to the if block: >> >>>> >> >>>> let x = 100; >> >>>> if (x > 50) { >> >>>> console.log(x); >> >>>> } >> >>>> // x is in scope, but may not be needed beyond the if statement >> >>>> console.log(x); >> >>>> >> >>>> // or a non-strict assignment, which also "leaks" scope >> >>>> if( (x = 100) > 50 ) { >> >>>> // ... >> >>>> } >> >>>> >> >>>> There are many "workarounds" available, here's a few: >> >>>> >> >>>> // workaround 1: can be remedied with a scope block >> >>>> // but it's asymmetrical and non-idiomatic >> >>>> { >> >>>> let x = 100; >> >>>> if (x > 50) { >> >>>> console.log(x); >> >>>> } >> >>>> } >> >>>> >> >>>> // workaround 2: with a for statement >> >>>> // but this is non-idiomatic, hard to read and error-prone >> >>>> for (let x = 100; x > 50;) { >> >>>> console.log(x); >> >>>> break; >> >>>> } >> >>>> >> >>>> If-initialization is available in many languages (Go, Perl and Ruby >> >>>> come to mind) and are considered best practice in each one of them: >> >>>> >> >>>> // Golang - x is defined, assigned and conditionally tested >> >>>> if x := 100; x > 50 { >> >>>> // x is in scope here >> >>>> } else { >> >>>> // and in here >> >>>> } >> >>>> // x is not available here >> >>>> >> >>>> ###### Perl >> >>>> if( my $x = 100 ) { >> >>>> print $x; >> >>>> } >> >>>> print $x; # an error >> >>>> >> >>>> if ( ( my $x = myfoo() ) > 50 ) { # also ok in Perl >> >>>> print $x; >> >>>> } >> >>>> >> >>>> ###### Ruby >> >>>> if ( x = 100 ) # parens required per style guide >> >>>> puts(x) >> >>>> end >> >>>> puts(x) # unfortunately Ruby does not limit scope to if, so x >> >>>> "leaks" >> >>>> >> >>>> I think this would be a great and important addition to the language. >> >>>> >> >>>> -Rodrigo >> >>>> >> >>>> PS: Just for the sake of comparison, Perl-style if-assignments could >> >>>> also be an >> >>>> option, albeit a very bad one IMO: >> >>>> >> >>>> if( ( let x = 100 ) > 50 ) { >> >>>> } >> >>>> >> >>>> A Perl-style, value-returning let/const has readability issues, opens >> >>>> quite a few fronts and sort of implies that let/const can return >> >>>> values anywhere in the code outside if/else. On the other hand it >> >>>> would fit with the currently if assignment if( x = y ). Definitely >> not >> >>>> recommended. >> >>>> _______________________________________________ >> >>>> es-discuss mailing list >> >>>> es-discuss at mozilla.org >> >>>> https://mail.mozilla.org/listinfo/es-discuss >> >>> >> >>> >> >>> _______________________________________________ >> >>> es-discuss mailing list >> >>> es-discuss at mozilla.org >> >>> https://mail.mozilla.org/listinfo/es-discuss >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180321/38f2723d/attachment-0001.html>
@thomas, no. i'm serious in my opinion that let and const were mistakes.
@thomas, no. i'm serious in my opinion that let and const were mistakes. -kai > On Mar 21, 2018, at 9:01 PM, Thomas Grainger <tagrain at gmail.com> wrote: > > Is this sarcastic? > > On 21 Mar 2018 12:58, "kai zhu" <kaizhu256 at gmail.com <mailto:kaizhu256 at gmail.com>> wrote: > this is why let and const should *never* have been introduced. if we had stuck with just var, none of these petty-arguments and bickering among team-members/shops on scoping-styles that ultimately have *zero* productivity or benefit to web-projects would be possible. > > and there's nothing wrong with pre-declaring all variables at the top-level of a function (which is an es5 best-practice that’s still valid today), regardless whether some are only used in conditional-blocks or not, like this real-world example [1]: > > ``` > local.validateBySwaggerSchema = function (options) { > /* > * this function will validate data against schema > * http://json-schema.org/draft-04/json-schema-validation.html#rfc.section.5 <http://json-schema.org/draft-04/json-schema-validation.html#rfc.section.5> > */ > var $ref, > circularList, > data, > dataReadonlyRemove2, > ii, > oneOf, > schema, > test, > tmp; > ... > // dereference schema.$ref > $ref = schema && schema.$ref; > if (!$ref) { > break; > } > ... > tmp = typeof data; > if (tmp === 'object' && Array.isArray(data)) { > tmp = 'array'; > } > ... > if (schema === local.swaggerSchemaJson.definitions.jsonReference) { > ... > } > ... > }; > ``` > > [1] https://github.com/kaizhu256/node-swgg/blob/2018.2.1/lib.swgg.js#L4076 <https://github.com/kaizhu256/node-swgg/blob/2018.2.1/lib.swgg.js#L4076> > > -kai > >> On Mar 21, 2018, at 7:15 PM, Jordan Harband <ljharb at gmail.com <mailto:ljharb at gmail.com>> wrote: >> >> ``` >> if (someComplicatedCondition()) { >> doSomeLogic(); >> doSomeOtherLogic(if.value, true); >> } >> ``` >> >> On Wed, Mar 21, 2018 at 2:52 AM, Rodrigo <rodrigolive at gmail.com <mailto:rodrigolive at gmail.com>> wrote: >> Here are my gripes with `let` and `const` returning values: >> >> 1) declaration lists are hard to read: >> >> if ((let x = 10, y = 20) > 15) { >> // true, but what's being compared here? 10 or 20? (answer: 20) >> } >> >> Although right now this is allowed and the last element is compared: >> >> if ((x = 10, y = 20) > 15) { >> // result is true, 20 > 15 >> } >> >> 2) Destructuring assignments are also confusing, what's being compared here? >> >> if(let [x,y] = [1,2]) { >> } >> >> Again, this is allowed as of today: >> >> if([x,y] = [1,2]) { >> // true, as it returns [1,2] >> } >> >> 3) Nesting `let/const` would be either expected everywhere (not only >> in the `if`) or a possible side effect from the implementation. >> Similar to languages such as Perl. >> >> let x = foo(let y = 100, z = 200); // what's the scope of x and z? >> >> This leads to hard to read and very confusing code golf. >> >> That's why Golang went with something simple, >> `if([declaration];[conditional])`, and avoided confusion over `:=` >> assignments returning values anywhere in the code. `x:=( y:= 20 )` is >> not allowed in Go. >> >> It expands on the 45-year tried-and-true structure of `for(;;)` to >> create `if(;)` and keep the ES language simple and clear expanding on >> its own concept of `for(;;)`. >> >> On Wed, Mar 21, 2018 at 7:57 AM, Naveen Chawla <naveen.chwl at gmail.com <mailto:naveen.chwl at gmail.com>> wrote: >> > OK I neglected to read the original post fully. My last post example would >> > be based on allowing `const` and `let` declarations to expressions in of >> > themselves (in the case of multi variables, returning the last one). So let >> > me ask, what exactly would be the problem with this? >> > >> > On Wed, 21 Mar 2018 at 12:20 Naveen Chawla <naveen.chwl at gmail.com <mailto:naveen.chwl at gmail.com>> wrote: >> >> >> >> What would `if.value` look like in an example? >> >> >> >> Wouldn't it be possible to have something like `if(const x = getX() && >> >> const y = getY())` to capture more than just the conditional if required? >> >> I'm guessing that would probably break something somewhere, but I'm not sure >> >> what. >> >> >> >> On Wed, 21 Mar 2018 at 04:35 Jordan Harband <ljharb at gmail.com <mailto:ljharb at gmail.com>> wrote: >> >>> >> >>> Is the use case only ever to capture the thing that serves as the >> >>> conditional? >> >>> >> >>> If so, would perhaps something like `if.value` work better? Since it's a >> >>> keyword, it could be made to only work in the `if` block, and you wouldn't >> >>> need any of that odd multi-statement stuff in the conditional parens. >> >>> >> >>> On Tue, Mar 20, 2018 at 12:57 PM, Rodrigo <rodrigolive at gmail.com <mailto:rodrigolive at gmail.com>> wrote: >> >>>> >> >>>> Proposal: inline let/const statements to declare and initialize >> >>>> variables within if statements, so that temporary variables exist only >> >>>> within the if/else block scope. >> >>>> >> >>>> Reason: limits variable scope to the block where really needed, in >> >>>> similar fashion to variables defined in for(;;) statements. This >> >>>> improves readability while reducing unnecessary variables roaming >> >>>> outside their needed block. >> >>>> >> >>>> The syntax would be very similar to the for(;;) assignment/test pair: >> >>>> >> >>>> if (let x = 100; x > 50) { >> >>>> console.log(x); // 100 >> >>>> } >> >>>> console.log(x); // ReferenceError >> >>>> >> >>>> // same for const >> >>>> if( const x = foo(); typeof x === 'object' ) { >> >>>> //... >> >>>> } >> >>>> >> >>>> // the variable is available within any else block >> >>>> // after its declaration >> >>>> if (let x = foo(); x < 50) { >> >>>> console.log(x); // y is not available here >> >>>> } else if (let y = bar(); y > 0) { >> >>>> console.log(x, y); >> >>>> } else { >> >>>> console.log(x, y); >> >>>> } >> >>>> >> >>>> Right now there isn't a way to limit a variable to the if block: >> >>>> >> >>>> let x = 100; >> >>>> if (x > 50) { >> >>>> console.log(x); >> >>>> } >> >>>> // x is in scope, but may not be needed beyond the if statement >> >>>> console.log(x); >> >>>> >> >>>> // or a non-strict assignment, which also "leaks" scope >> >>>> if( (x = 100) > 50 ) { >> >>>> // ... >> >>>> } >> >>>> >> >>>> There are many "workarounds" available, here's a few: >> >>>> >> >>>> // workaround 1: can be remedied with a scope block >> >>>> // but it's asymmetrical and non-idiomatic >> >>>> { >> >>>> let x = 100; >> >>>> if (x > 50) { >> >>>> console.log(x); >> >>>> } >> >>>> } >> >>>> >> >>>> // workaround 2: with a for statement >> >>>> // but this is non-idiomatic, hard to read and error-prone >> >>>> for (let x = 100; x > 50;) { >> >>>> console.log(x); >> >>>> break; >> >>>> } >> >>>> >> >>>> If-initialization is available in many languages (Go, Perl and Ruby >> >>>> come to mind) and are considered best practice in each one of them: >> >>>> >> >>>> // Golang - x is defined, assigned and conditionally tested >> >>>> if x := 100; x > 50 { >> >>>> // x is in scope here >> >>>> } else { >> >>>> // and in here >> >>>> } >> >>>> // x is not available here >> >>>> >> >>>> ###### Perl >> >>>> if( my $x = 100 ) { >> >>>> print $x; >> >>>> } >> >>>> print $x; # an error >> >>>> >> >>>> if ( ( my $x = myfoo() ) > 50 ) { # also ok in Perl >> >>>> print $x; >> >>>> } >> >>>> >> >>>> ###### Ruby >> >>>> if ( x = 100 ) # parens required per style guide >> >>>> puts(x) >> >>>> end >> >>>> puts(x) # unfortunately Ruby does not limit scope to if, so x >> >>>> "leaks" >> >>>> >> >>>> I think this would be a great and important addition to the language. >> >>>> >> >>>> -Rodrigo >> >>>> >> >>>> PS: Just for the sake of comparison, Perl-style if-assignments could >> >>>> also be an >> >>>> option, albeit a very bad one IMO: >> >>>> >> >>>> if( ( let x = 100 ) > 50 ) { >> >>>> } >> >>>> >> >>>> A Perl-style, value-returning let/const has readability issues, opens >> >>>> quite a few fronts and sort of implies that let/const can return >> >>>> values anywhere in the code outside if/else. On the other hand it >> >>>> would fit with the currently if assignment if( x = y ). Definitely not >> >>>> recommended. >> >>>> _______________________________________________ >> >>>> es-discuss mailing list >> >>>> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> >> >>>> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> >> >>> >> >>> >> >>> _______________________________________________ >> >>> es-discuss mailing list >> >>> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> >> >>> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> >> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> >> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> > https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180321/aff7b9e8/attachment-0001.html>
On Tue, Mar 20, 2018 at 3:57 PM, Rodrigo <rodrigolive at gmail.com> wrote:
Proposal: inline let/const statements to declare and initialize variables within if statements, so that temporary variables exist only within the if/else block scope.
With setters you can get some oddities because the getter need not return the same value set.
const o = { get x() { return this.x_ }, set x(v) { return this.x_ = String(v) } } if (!(o.x = 0)) { console.log('o.x is falsey: ' + !o.x); }
If decorators tc39/proposal-decorators#51 are
allowed on let/const declarations, then you might get a similar source of confusion.
This might be especially confusing since in Java and C++ the result of an assignment is the value actually assigned after any type coercion (or a reference to the left).
In JavaScript, the result of an assignment is the result of the right operand. Though its a bit muddy, since the result of x++ is x coerced to a number for symmetry with x += 1.
If it turns out that decorators are widely used for type annotations on declarations and some do custom coercion on assignment, does that introduce potential problems?
On Tue, Mar 20, 2018 at 3:57 PM, Rodrigo <rodrigolive at gmail.com> wrote: > Proposal: inline let/const statements to declare and initialize > variables within if statements, so that temporary variables exist only > within the if/else block scope. > With setters you can get some oddities because the getter need not return the same value set. const o = { get x() { return this.x_ }, set x(v) { return this.x_ = String(v) } } if (!(o.x = 0)) { console.log('o.x is falsey: ' + !o.x); } If decorators <https://github.com/tc39/proposal-decorators/issues/51> are allowed on let/const declarations, then you might get a similar source of confusion. This might be especially confusing since in Java and C++ the result of an assignment is the value actually assigned after any type coercion (or a reference to the left). In JavaScript, the result of an assignment is the result of the right operand. Though its a bit muddy, since the result of x++ is x coerced to a number for symmetry with x += 1. If it turns out that decorators are widely used for type annotations on declarations and some do custom coercion on assignment, does that introduce potential problems? -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180321/dbe2ac17/attachment.html>
My proposal is to keep it simple and implement the if-assignment if( const o = ...; ! o ) { ... }
mimicking the for(;;)
assignment
behavior.
That way we can scope a variable to the if
block and we can do that
separately from assignment.
Assigning and comparing at the same time opens up all sort of oddities as the variable transitions from lvalue to comparison operand. This already exists in the language and is definitely not good practice.
if.value
, as proposed earlier is a bombshell similar to this
,
which could easily get scrambled with the introduction of additional
if
blocks.
The beauty of if(;)
is that it makes scope blocks possible while
avoiding the asymmetric behavior caused by assigning and comparing in
one go.
if( let people=getTeamArray(); people.length > 2 ) {
console.log("it's a crowd", people.join(','));
}
else if( people.length == 2 ) {
console.log("just a pair");
}
else if( people.length == 1 {
console.log("solo");
}
else {
console.log("none");
}
My proposal is to keep it simple and implement the if-assignment `if( const o = ...; ! o ) { ... }` mimicking the `for(;;)` assignment behavior. That way we can scope a variable to the `if` block and we can do that *separately* from assignment. Assigning and comparing at the same time opens up all sort of oddities as the variable transitions from lvalue to comparison operand. This already exists in the language and is definitely not good practice. `if.value`, as proposed earlier is a bombshell similar to `this`, which could easily get scrambled with the introduction of additional `if` blocks. The beauty of `if(;)` is that it makes scope blocks possible while avoiding the asymmetric behavior caused by assigning and comparing in one go. if( let people=getTeamArray(); people.length > 2 ) { console.log("it's a crowd", people.join(',')); } else if( people.length == 2 ) { console.log("just a pair"); } else if( people.length == 1 { console.log("solo"); } else { console.log("none"); } On Wed, Mar 21, 2018 at 2:37 PM, Mike Samuel <mikesamuel at gmail.com> wrote: > > > On Tue, Mar 20, 2018 at 3:57 PM, Rodrigo <rodrigolive at gmail.com> wrote: >> >> Proposal: inline let/const statements to declare and initialize >> variables within if statements, so that temporary variables exist only >> within the if/else block scope. > > > With setters you can get some oddities because the getter need not return > the same value set. > > const o = { get x() { return this.x_ }, set x(v) { return this.x_ = > String(v) } } > if (!(o.x = 0)) { > console.log('o.x is falsey: ' + !o.x); > } > > If decorators are allowed on let/const declarations, then you might get a > similar source of > confusion. > > This might be especially confusing since in Java and C++ the result of an > assignment is > the value actually assigned after any type coercion (or a reference to the > left). > > In JavaScript, the result of an assignment is the result of the right > operand. > Though its a bit muddy, since the result of x++ is x coerced to a number for > symmetry with x += 1. > > If it turns out that decorators are widely used for type annotations on > declarations and > some do custom coercion on assignment, does that introduce potential > problems? > > > > >
On Wed, Mar 21, 2018 at 11:02 AM, Rodrigo <rodrigolive at gmail.com> wrote:
My proposal is to keep it simple and implement the if-assignment
if( const o = ...; ! o ) { ... }
mimicking thefor(;;)
assignment behavior.
Fair enough. If the assignment is separate from the condition, then none of that matters. That question only pertained to let/const declarations used for their value.
That way we can scope a variable to the if
block and we can do that
separately from assignment.
Assigning and comparing at the same time opens up all sort of oddities as the variable transitions from lvalue to comparison operand. This already exists in the language and is definitely not good practice.
if.value
, as proposed earlier is a bombshell similar tothis
, which could easily get scrambled with the introduction of additionalif
blocks.The beauty of
if(;)
is that it makes scope blocks possible while avoiding the asymmetric behavior caused by assigning and comparing in one go.if( let people=getTeamArray(); people.length > 2 ) { console.log("it's a crowd", people.join(',')); } else if( people.length == 2 ) { console.log("just a pair"); } else if( people.length == 1 { console.log("solo"); } else { console.log("none"); }
IIUC, it sounds like the right side could be syntactic sugar for the left side. If that's right, what about the left side warrants new syntax to enable the right?
CurrentProposed
{ let people = getTeamArray(); if( people.length > 2 ) { console.log("it's a crowd", people.join(',')); } else if( people.length == 2 ) { console.log("just a pair"); } else if( people.length == 1 { console.log("solo"); } else { console.log("none"); } }
if( let people = getTeamArray(); people.length > 2 ) { console.log("it's a crowd", people.join(',')); } else if( people.length == 2 ) { console.log("just a pair"); } else if( people.length == 1 { console.log("solo"); } else { console.log("none"); }
I can imagine that it might be nice when used later in an else-if chain:
if (c0) { ... } else (let x = v1, c1(x)) { ... } else ...
vs
if (c0) { ... } else { let x = v1; if (c1(x)) { ... } else ... }
Can you point at any particularly tricky code that could be simplified by this?
On Wed, Mar 21, 2018 at 11:02 AM, Rodrigo <rodrigolive at gmail.com> wrote: > My proposal is to keep it simple and implement the if-assignment `if( > const o = ...; ! o ) { ... }` mimicking the `for(;;)` assignment > behavior. > Fair enough. If the assignment is separate from the condition, then none of that matters. That question only pertained to let/const declarations used for their value. That way we can scope a variable to the `if` block and we can do that > *separately* from assignment. > > Assigning and comparing at the same time opens up all sort of oddities > as the variable transitions from lvalue to comparison operand. This > already exists in the language and is definitely not good practice. > > `if.value`, as proposed earlier is a bombshell similar to `this`, > which could easily get scrambled with the introduction of additional > `if` blocks. > > The beauty of `if(;)` is that it makes scope blocks possible while > avoiding the asymmetric behavior caused by assigning and comparing in > one go. > > if( let people=getTeamArray(); people.length > 2 ) { > console.log("it's a crowd", people.join(',')); > } > else if( people.length == 2 ) { > console.log("just a pair"); > } > else if( people.length == 1 { > console.log("solo"); > } > else { > console.log("none"); > } > IIUC, it sounds like the right side could be syntactic sugar for the left side. If that's right, what about the left side warrants new syntax to enable the right? CurrentProposed { *let people = getTeamArray();* if( people.length > 2 ) { console.log("it's a crowd", people.join(',')); } else if( people.length == 2 ) { console.log("just a pair"); } else if( people.length == 1 { console.log("solo"); } else { console.log("none"); } } if( *let people = getTeamArray();* people.length > 2 ) { console.log("it's a crowd", people.join(',')); } else if( people.length == 2 ) { console.log("just a pair"); } else if( people.length == 1 { console.log("solo"); } else { console.log("none"); } I can imagine that it might be nice when used later in an else-if chain: if (c0) { ... } else (let x = v1, c1(x)) { ... } else ... vs if (c0) { ... } else { let x = v1; if (c1(x)) { ... } else ... } Can you point at any particularly tricky code that could be simplified by this? -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180321/06e385d1/attachment-0001.html>
how is any of this less-confusing than a simple style-guide of pre-declaring all variables @ the beginning of a function? again, there’s zero legitimate reason why javascript even needs block-level scoping of variables (and arguing because other languages have it is not a reason). you're just creating more needless javascript style-guide variance that further confuses your team-members / project-successor.
/*jslint
bitwise: true,
browser: true,
maxerr: 8,
maxlen: 100,
node: true,
nomen: true,
regexp: true,
stupid: true
*/
(function () {
'use strict';
// es5 best-practice of declaring all variables at beginning of function,
// and runtime-checked by 'use strict' pragma
var bar,
c0,
c1,
foo,
getTeamArray,
people,
v1,
xx,
yy;
getTeamArray = function () {
return [1, 2, 3];
};
people = getTeamArray();
if (people.length > 2) {
console.log("it's a crowd", people.join(','));
} else if (people.length === 2) {
console.log("just a pair");
} else if (people.length === 1) {
console.log("solo");
} else {
console.log("none");
}
// output: it's a crowd 1,2,3
bar = function () {
return 0;
};
foo = function () {
return 50;
};
(function () {
xx = foo();
if (xx < 50) {
console.log(xx); // yy is not available here
return;
}
yy = bar();
if (yy > 0) {
console.log(yy);
return;
}
// else
console.log(xx, yy);
}());
// output: 50 0
c0 = null;
c1 = function (xx) {
return xx;
};
v1 = false;
// 'unset' xx
xx = undefined;
(function () {
if (c0) {
console.log(c0); // xx is not available here
return;
}
xx = v1;
if (c1(xx)) {
console.log(xx);
return;
}
// else
console.log(c0, xx);
}());
// output: null false
}());
how is any of this less-confusing than a simple style-guide of pre-declaring all variables @ the beginning of a function? again, there’s zero legitimate reason why javascript even needs block-level scoping of variables (and arguing because other languages have it is not a reason). you're just creating more needless javascript style-guide variance that further confuses your team-members / project-successor. ``` /*jslint bitwise: true, browser: true, maxerr: 8, maxlen: 100, node: true, nomen: true, regexp: true, stupid: true */ (function () { 'use strict'; // es5 best-practice of declaring all variables at beginning of function, // and runtime-checked by 'use strict' pragma var bar, c0, c1, foo, getTeamArray, people, v1, xx, yy; getTeamArray = function () { return [1, 2, 3]; }; people = getTeamArray(); if (people.length > 2) { console.log("it's a crowd", people.join(',')); } else if (people.length === 2) { console.log("just a pair"); } else if (people.length === 1) { console.log("solo"); } else { console.log("none"); } // output: it's a crowd 1,2,3 bar = function () { return 0; }; foo = function () { return 50; }; (function () { xx = foo(); if (xx < 50) { console.log(xx); // yy is not available here return; } yy = bar(); if (yy > 0) { console.log(yy); return; } // else console.log(xx, yy); }()); // output: 50 0 c0 = null; c1 = function (xx) { return xx; }; v1 = false; // 'unset' xx xx = undefined; (function () { if (c0) { console.log(c0); // xx is not available here return; } xx = v1; if (c1(xx)) { console.log(xx); return; } // else console.log(c0, xx); }()); // output: null false }()); ``` > On Mar 22, 2018, at 1:56 AM, Mike Samuel <mikesamuel at gmail.com> wrote: > > > > On Wed, Mar 21, 2018 at 11:02 AM, Rodrigo <rodrigolive at gmail.com <mailto:rodrigolive at gmail.com>> wrote: > My proposal is to keep it simple and implement the if-assignment `if( > const o = ...; ! o ) { ... }` mimicking the `for(;;)` assignment > behavior. > > Fair enough. If the assignment is separate from the condition, then none of that matters. > That question only pertained to let/const declarations used for their value. > > That way we can scope a variable to the `if` block and we can do that > *separately* from assignment. > > Assigning and comparing at the same time opens up all sort of oddities > as the variable transitions from lvalue to comparison operand. This > already exists in the language and is definitely not good practice. > > `if.value`, as proposed earlier is a bombshell similar to `this`, > which could easily get scrambled with the introduction of additional > `if` blocks. > > The beauty of `if(;)` is that it makes scope blocks possible while > avoiding the asymmetric behavior caused by assigning and comparing in > one go. > > if( let people=getTeamArray(); people.length > 2 ) { > console.log("it's a crowd", people.join(',')); > } > else if( people.length == 2 ) { > console.log("just a pair"); > } > else if( people.length == 1 { > console.log("solo"); > } > else { > console.log("none"); > } > > IIUC, it sounds like the right side could be syntactic sugar for the left side. > If that's right, what about the left side warrants new syntax to enable the right? > > > Current Proposed > { > let people = getTeamArray(); > if( people.length > 2 ) { > console.log("it's a crowd", people.join(',')); > } > else if( people.length == 2 ) { > console.log("just a pair"); > } > else if( people.length == 1 { > console.log("solo"); > } > else { > console.log("none"); > } > } > if( let people = getTeamArray(); people.length > 2 ) { > console.log("it's a crowd", people.join(',')); > } > else if( people.length == 2 ) { > console.log("just a pair"); > } > else if( people.length == 1 { > console.log("solo"); > } > else { > console.log("none"); > } > > I can imagine that it might be nice when used later in an else-if chain: > > if (c0) { > ... > } else (let x = v1, c1(x)) { > ... > } else ... > > vs > > if (c0) { > ... > } else { > let x = v1; > if (c1(x)) { > ... > } else ... > } > > Can you point at any particularly tricky code that could be simplified by this? > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> > https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180322/85e57da1/attachment.html>
An HTML attachment was scrubbed... URL: esdiscuss/attachments/20180321/66c2555e/attachment-0001
An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180321/66c2555e/attachment-0001.html>
This is just trolling that seems intended to derail the discussion.
This is just trolling that seems intended to derail the discussion. On Wed, Mar 21, 2018 at 10:21 AM, kai zhu <kaizhu256 at gmail.com> wrote: > how is any of this less-confusing than a simple style-guide of > pre-declaring all variables @ the beginning of a function? > again, there’s zero legitimate reason why javascript even needs > block-level scoping of variables (and arguing because other languages have > it is not a reason). you're just creating more needless javascript > style-guide variance that further confuses your team-members / > project-successor. > > ``` > /*jslint > bitwise: true, > browser: true, > maxerr: 8, > maxlen: 100, > node: true, > nomen: true, > regexp: true, > stupid: true > */ > (function () { > 'use strict'; > // es5 best-practice of declaring all variables at beginning of > function, > // and runtime-checked by 'use strict' pragma > var bar, > c0, > c1, > foo, > getTeamArray, > people, > v1, > xx, > yy; > > > > getTeamArray = function () { > return [1, 2, 3]; > }; > people = getTeamArray(); > if (people.length > 2) { > console.log("it's a crowd", people.join(',')); > } else if (people.length === 2) { > console.log("just a pair"); > } else if (people.length === 1) { > console.log("solo"); > } else { > console.log("none"); > } > // output: it's a crowd 1,2,3 > > > > bar = function () { > return 0; > }; > foo = function () { > return 50; > }; > (function () { > xx = foo(); > if (xx < 50) { > console.log(xx); // yy is not available here > return; > } > yy = bar(); > if (yy > 0) { > console.log(yy); > return; > } > // else > console.log(xx, yy); > }()); > // output: 50 0 > > > > c0 = null; > c1 = function (xx) { > return xx; > }; > v1 = false; > // 'unset' xx > xx = undefined; > (function () { > if (c0) { > console.log(c0); // xx is not available here > return; > } > xx = v1; > if (c1(xx)) { > console.log(xx); > return; > } > // else > console.log(c0, xx); > }()); > // output: null false > }()); > ``` > > On Mar 22, 2018, at 1:56 AM, Mike Samuel <mikesamuel at gmail.com> wrote: > > > > On Wed, Mar 21, 2018 at 11:02 AM, Rodrigo <rodrigolive at gmail.com> wrote: > >> My proposal is to keep it simple and implement the if-assignment `if( >> const o = ...; ! o ) { ... }` mimicking the `for(;;)` assignment >> behavior. >> > > Fair enough. If the assignment is separate from the condition, then none > of that matters. > That question only pertained to let/const declarations used for their > value. > > That way we can scope a variable to the `if` block and we can do that >> *separately* from assignment. >> >> Assigning and comparing at the same time opens up all sort of oddities >> as the variable transitions from lvalue to comparison operand. This >> already exists in the language and is definitely not good practice. >> >> `if.value`, as proposed earlier is a bombshell similar to `this`, >> which could easily get scrambled with the introduction of additional >> `if` blocks. >> >> The beauty of `if(;)` is that it makes scope blocks possible while >> avoiding the asymmetric behavior caused by assigning and comparing in >> one go. >> >> if( let people=getTeamArray(); people.length > 2 ) { >> console.log("it's a crowd", people.join(',')); >> } >> else if( people.length == 2 ) { >> console.log("just a pair"); >> } >> else if( people.length == 1 { >> console.log("solo"); >> } >> else { >> console.log("none"); >> } >> > > IIUC, it sounds like the right side could be syntactic sugar for the left > side. > If that's right, what about the left side warrants new syntax to enable > the right? > > > CurrentProposed > > { > *let people = getTeamArray();* > if( people.length > 2 ) { > console.log("it's a crowd", people.join(',')); > } > else if( people.length == 2 ) { > console.log("just a pair"); > } > else if( people.length == 1 { > console.log("solo"); > } > else { > console.log("none"); > } > } > > if( *let people = getTeamArray();* people.length > 2 ) { > console.log("it's a crowd", people.join(',')); > } > else if( people.length == 2 ) { > console.log("just a pair"); > } > else if( people.length == 1 { > console.log("solo"); > } > else { > console.log("none"); > } > > > I can imagine that it might be nice when used later in an else-if chain: > > if (c0) { > ... > } else (let x = v1, c1(x)) { > ... > } else ... > > vs > > if (c0) { > ... > } else { > let x = v1; > if (c1(x)) { > ... > } else ... > } > > Can you point at any particularly tricky code that could be simplified by > this? > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180321/68ccc795/attachment.html>
I have used the desugared version and found that what seemed obvious to me, that the purpose of the block was to limit the scope, was not obvious to other developers on my team. If this proposal moves forward I think it should include switch and while in addition to if.
On Wednesday, March 21, 2018, 11:56:08 AM CDT, Mike Samuel <mikesamuel at gmail.com> wrote:
[...]IIUC, it sounds like the right side could be syntactic sugar for the left side.If that's right, what about the left side warrants new syntax to enable the right?
| Current | Proposed | | { let people = getTeamArray(); if( people.length > 2 ) { console.log("it's a crowd", people.join(',')); } else if( people.length == 2 ) { console.log("just a pair"); } else if( people.length == 1 { console.log("solo"); } else { console.log("none"); } } | if( let people = getTeamArray(); people.length > 2 ) { console.log("it's a crowd", people.join(',')); } else if( people.length == 2 ) { console.log("just a pair"); } else if( people.length == 1 { console.log("solo"); } else { console.log("none"); } |
[...]
I have used the desugared version and found that what seemed obvious to me, that the purpose of the block was to limit the scope, was not obvious to other developers on my team. If this proposal moves forward I think it should include switch and while in addition to if. On Wednesday, March 21, 2018, 11:56:08 AM CDT, Mike Samuel <mikesamuel at gmail.com> wrote: [...]IIUC, it sounds like the right side could be syntactic sugar for the left side.If that's right, what about the left side warrants new syntax to enable the right? | Current | Proposed | | { let people = getTeamArray(); if( people.length > 2 ) { console.log("it's a crowd", people.join(',')); } else if( people.length == 2 ) { console.log("just a pair"); } else if( people.length == 1 { console.log("solo"); } else { console.log("none"); } } | if( let people = getTeamArray(); people.length > 2 ) { console.log("it's a crowd", people.join(',')); } else if( people.length == 2 ) { console.log("just a pair"); } else if( people.length == 1 { console.log("solo"); } else { console.log("none"); } | [...] _______________________________________________ es-discuss mailing list es-discuss at mozilla.org https://mail.mozilla.org/listinfo/es-discuss -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180321/31d61413/attachment-0001.html>
i'm not trolling. unlike javascript, most other languages deal near exclusively with blocking-code, which is only applicable to low-level library-code in javascript (that pretty much anyone can write). at higher-level integration-stuff dealing with non-blocking io, these blocking-code design-patterns from other languages are pretty-much useless. like say … block-level scoping, because it doesn’t mix well with closures, which are heavily used in integration-level javascript to keep track of states for non-blocking code.
e.g.
/*jslint
bitwise: true,
browser: true,
maxerr: 8,
maxlen: 200,
node: true,
nomen: true,
regexp: true,
stupid: true
*/
(function () {
'use strict';
var chunkList, request, response, timerTimeout;
chunkList = [];
// auto-timeout and cleanup closure-vars request and response after 30000 ms
timerTimeout = setTimeout(function () {
try {
request.destroy();
} catch (ignore) {
}
try {
response.destroy();
} catch (ignore) {
}
console.error('timeout error after 30000 ms');
}, 30000);
request = require('https').request(
require('url').parse('https://www.example.com'),
function (_response) {
response = _response;
response.on('data', function (chunk) {
// append chunk to closure-var chunkList
chunkList.push(chunk);
});
response.on('end', function () {
// print closure-var chunkList to stdout
console.log(Buffer.concat(chunkList).toString());
// cancel closure-var timerTimeout,
// after request successfully completes
clearTimeout(timerTimeout);
});
}
);
request.end();
/*
output:
<!doctype html>
<html>
<head>
<title>Example Domain</title>
...
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is established to be used for illustrative examples in documents. You may use this
domain in examples without prior coordination or asking for permission.</p>
<p><a href="http://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
*/
}());
i'm not trolling. unlike javascript, most other languages deal near exclusively with blocking-code, which is only applicable to low-level library-code in javascript (that pretty much anyone can write). at higher-level integration-stuff dealing with non-blocking io, these blocking-code design-patterns from other languages are pretty-much useless. like say … *block-level scoping*, because it doesn’t mix well with closures, which are heavily used in integration-level javascript to keep track of states for non-blocking code. e.g. ``` /*jslint bitwise: true, browser: true, maxerr: 8, maxlen: 200, node: true, nomen: true, regexp: true, stupid: true */ (function () { 'use strict'; var chunkList, request, response, timerTimeout; chunkList = []; // auto-timeout and cleanup closure-vars request and response after 30000 ms timerTimeout = setTimeout(function () { try { request.destroy(); } catch (ignore) { } try { response.destroy(); } catch (ignore) { } console.error('timeout error after 30000 ms'); }, 30000); request = require('https').request( require('url').parse('https://www.example.com'), function (_response) { response = _response; response.on('data', function (chunk) { // append chunk to closure-var chunkList chunkList.push(chunk); }); response.on('end', function () { // print closure-var chunkList to stdout console.log(Buffer.concat(chunkList).toString()); // cancel closure-var timerTimeout, // after request successfully completes clearTimeout(timerTimeout); }); } ); request.end(); /* output: <!doctype html> <html> <head> <title>Example Domain</title> ... </head> <body> <div> <h1>Example Domain</h1> <p>This domain is established to be used for illustrative examples in documents. You may use this domain in examples without prior coordination or asking for permission.</p> <p><a href="http://www.iana.org/domains/example">More information...</a></p> </div> </body> </html> */ }()); ``` > On Mar 22, 2018, at 2:31 AM, Christopher Thorn <morphcham at gmail.com> wrote: > > This is just trolling that seems intended to derail the discussion. > > On Wed, Mar 21, 2018 at 10:21 AM, kai zhu <kaizhu256 at gmail.com <mailto:kaizhu256 at gmail.com>> wrote: > how is any of this less-confusing than a simple style-guide of pre-declaring all variables @ the beginning of a function? > again, there’s zero legitimate reason why javascript even needs block-level scoping of variables (and arguing because other languages have it is not a reason). you're just creating more needless javascript style-guide variance that further confuses your team-members / project-successor. > > ``` > /*jslint > bitwise: true, > browser: true, > maxerr: 8, > maxlen: 100, > node: true, > nomen: true, > regexp: true, > stupid: true > */ > (function () { > 'use strict'; > // es5 best-practice of declaring all variables at beginning of function, > // and runtime-checked by 'use strict' pragma > var bar, > c0, > c1, > foo, > getTeamArray, > people, > v1, > xx, > yy; > > > > getTeamArray = function () { > return [1, 2, 3]; > }; > people = getTeamArray(); > if (people.length > 2) { > console.log("it's a crowd", people.join(',')); > } else if (people.length === 2) { > console.log("just a pair"); > } else if (people.length === 1) { > console.log("solo"); > } else { > console.log("none"); > } > // output: it's a crowd 1,2,3 > > > > bar = function () { > return 0; > }; > foo = function () { > return 50; > }; > (function () { > xx = foo(); > if (xx < 50) { > console.log(xx); // yy is not available here > return; > } > yy = bar(); > if (yy > 0) { > console.log(yy); > return; > } > // else > console.log(xx, yy); > }()); > // output: 50 0 > > > > c0 = null; > c1 = function (xx) { > return xx; > }; > v1 = false; > // 'unset' xx > xx = undefined; > (function () { > if (c0) { > console.log(c0); // xx is not available here > return; > } > xx = v1; > if (c1(xx)) { > console.log(xx); > return; > } > // else > console.log(c0, xx); > }()); > // output: null false > }()); > ``` > >> On Mar 22, 2018, at 1:56 AM, Mike Samuel <mikesamuel at gmail.com <mailto:mikesamuel at gmail.com>> wrote: >> >> >> >> On Wed, Mar 21, 2018 at 11:02 AM, Rodrigo <rodrigolive at gmail.com <mailto:rodrigolive at gmail.com>> wrote: >> My proposal is to keep it simple and implement the if-assignment `if( >> const o = ...; ! o ) { ... }` mimicking the `for(;;)` assignment >> behavior. >> >> Fair enough. If the assignment is separate from the condition, then none of that matters. >> That question only pertained to let/const declarations used for their value. >> >> That way we can scope a variable to the `if` block and we can do that >> *separately* from assignment. >> >> Assigning and comparing at the same time opens up all sort of oddities >> as the variable transitions from lvalue to comparison operand. This >> already exists in the language and is definitely not good practice. >> >> `if.value`, as proposed earlier is a bombshell similar to `this`, >> which could easily get scrambled with the introduction of additional >> `if` blocks. >> >> The beauty of `if(;)` is that it makes scope blocks possible while >> avoiding the asymmetric behavior caused by assigning and comparing in >> one go. >> >> if( let people=getTeamArray(); people.length > 2 ) { >> console.log("it's a crowd", people.join(',')); >> } >> else if( people.length == 2 ) { >> console.log("just a pair"); >> } >> else if( people.length == 1 { >> console.log("solo"); >> } >> else { >> console.log("none"); >> } >> >> IIUC, it sounds like the right side could be syntactic sugar for the left side. >> If that's right, what about the left side warrants new syntax to enable the right? >> >> >> Current Proposed >> { >> let people = getTeamArray(); >> if( people.length > 2 ) { >> console.log("it's a crowd", people.join(',')); >> } >> else if( people.length == 2 ) { >> console.log("just a pair"); >> } >> else if( people.length == 1 { >> console.log("solo"); >> } >> else { >> console.log("none"); >> } >> } >> if( let people = getTeamArray(); people.length > 2 ) { >> console.log("it's a crowd", people.join(',')); >> } >> else if( people.length == 2 ) { >> console.log("just a pair"); >> } >> else if( people.length == 1 { >> console.log("solo"); >> } >> else { >> console.log("none"); >> } >> >> I can imagine that it might be nice when used later in an else-if chain: >> >> if (c0) { >> ... >> } else (let x = v1, c1(x)) { >> ... >> } else ... >> >> vs >> >> if (c0) { >> ... >> } else { >> let x = v1; >> if (c1(x)) { >> ... >> } else ... >> } >> >> Can you point at any particularly tricky code that could be simplified by this? >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> >> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> > https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180322/1cec077e/attachment-0001.html>
On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <sebastian at malton.name>
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.
On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <sebastian at malton.name> 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. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180321/38bfd3ca/attachment.html>
TIL
On Wed, Mar 21, 2018 at 2:29 PM, kai zhu <kaizhu256 at gmail.com> wrote:
/*jslint
stupid: true
*/
TIL On Wed, Mar 21, 2018 at 2:29 PM, kai zhu <kaizhu256 at gmail.com> wrote: > /*jslint > stupid: true > */ > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180321/52d12b30/attachment.html>
@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.
@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 <mikesamuel at gmail.com> wrote: > > > > On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <sebastian at malton.name <mailto:sebastian at malton.name>> 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. > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180322/c5dad1f4/attachment-0001.html>
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 me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
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 me at isiahmeadows.com 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 <mikesamuel at gmail.com> wrote: > > > On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <sebastian at malton.name> > 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 > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss >
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: isiahmeadows at gmail.com Sent: March 21, 2018 6:18 PM To: mikesamuel at gmail.com Cc: sebastian at malton.name; es-discuss at mozilla.org 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 me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
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: isiahmeadows at gmail.com Sent: March 21, 2018 6:18 PM To: mikesamuel at gmail.com Cc: sebastian at malton.name; es-discuss at mozilla.org 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 me at isiahmeadows.com 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 <mikesamuel at gmail.com> wrote: > > > On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <sebastian at malton.name> > 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 > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss >
My implication was that it'd only be available in the if
(if
declared with let
/const
).
Isiah Meadows me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
My implication was that it'd only be available in the `if` (if declared with `let`/`const`). ----- Isiah Meadows me at isiahmeadows.com 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 <sebastian at malton.name> 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: isiahmeadows at gmail.com > Sent: March 21, 2018 6:18 PM > To: mikesamuel at gmail.com > Cc: sebastian at malton.name; es-discuss at mozilla.org > 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 > me at isiahmeadows.com > > 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 <mikesamuel at gmail.com> wrote: >> >> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <sebastian at malton.name> >> 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 >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >>
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.
Isiah Meadows me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
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 me at isiahmeadows.com 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 <kaizhu256 at gmail.com> 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 <mikesamuel at gmail.com> wrote: > > > > On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <sebastian at malton.name> > 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 > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss >
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 <mikesamuel at gmail.com> escribió:
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 <mikesamuel at gmail.com> escribió: > > > On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <sebastian at malton.name> > 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 > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180322/70076b7b/attachment.html>
<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: esdiscuss.org/topic/revive-let-blocks
- How it ended: 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:
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 me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
<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 me at isiahmeadows.com 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 <rodrigolive at gmail.com> 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 <mikesamuel at gmail.com> escribió: >> >> >> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <sebastian at malton.name> >> 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 >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss >
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.
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 <isiahmeadows at gmail.com> 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 > me at isiahmeadows.com > > 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 <rodrigolive at gmail.com> 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 <mikesamuel at gmail.com> escribió: >>> >>> >>> >>> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton <sebastian at malton.name> >>> 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 >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >>
On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <isiahmeadows at gmail.com>
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 theelse
so it can't be confused with anelse
within anif
.
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() || ({} => { ... })()
?
On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <isiahmeadows at gmail.com> 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 > me at isiahmeadows.com > > 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 <rodrigolive at gmail.com> 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 <mikesamuel at gmail.com> > escribió: > >> > >> > >> > >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton < > sebastian at malton.name> > >> 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 > >> es-discuss at mozilla.org > >> https://mail.mozilla.org/listinfo/es-discuss > > > > > > _______________________________________________ > > es-discuss mailing list > > es-discuss at mozilla.org > > https://mail.mozilla.org/listinfo/es-discuss > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180322/84be729a/attachment.html>
That strikes me as territory the 'do expression' proposal 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.
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 <mikesamuel at gmail.com> wrote: > On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <isiahmeadows at gmail.com> > 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 >> me at isiahmeadows.com >> >> 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 <rodrigolive at gmail.com> 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 <mikesamuel at gmail.com> >> escribió: >> >> >> >> >> >> >> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton < >> sebastian at malton.name> >> >> 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 >> >> es-discuss at mozilla.org >> >> https://mail.mozilla.org/listinfo/es-discuss >> > >> > >> > _______________________________________________ >> > es-discuss mailing list >> > es-discuss at mozilla.org >> > https://mail.mozilla.org/listinfo/es-discuss >> > >> > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180322/f70b59b2/attachment.html>
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:
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 me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
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 me at isiahmeadows.com 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 <rosyatrandom at gmail.com> 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 <mikesamuel at gmail.com> wrote: >> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <isiahmeadows at gmail.com> >> 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 >>> me at isiahmeadows.com >>> >>> 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 <rodrigolive at gmail.com> 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 <mikesamuel at gmail.com> >>> > escribió: >>> >> >>> >> >>> >> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton >>> >> <sebastian at malton.name> >>> >> 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 >>> >> es-discuss at mozilla.org >>> >> https://mail.mozilla.org/listinfo/es-discuss >>> > >>> > >>> > _______________________________________________ >>> > es-discuss mailing list >>> > es-discuss at mozilla.org >>> > https://mail.mozilla.org/listinfo/es-discuss >>> > >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss
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).
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 <isiahmeadows at gmail.com> 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 > me at isiahmeadows.com > > 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 > <rosyatrandom at gmail.com> 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 <mikesamuel at gmail.com> wrote: > >> > >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <isiahmeadows at gmail.com> > >> 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 > >>> me at isiahmeadows.com > >>> > >>> 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 <rodrigolive at gmail.com> > 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 <mikesamuel at gmail.com> > >>> > escribió: > >>> >> > >>> >> > >>> >> > >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton > >>> >> <sebastian at malton.name> > >>> >> 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 > >>> >> es-discuss at mozilla.org > >>> >> https://mail.mozilla.org/listinfo/es-discuss > >>> > > >>> > > >>> > _______________________________________________ > >>> > es-discuss mailing list > >>> > es-discuss at mozilla.org > >>> > https://mail.mozilla.org/listinfo/es-discuss > >>> > > >> > >> _______________________________________________ > >> es-discuss mailing list > >> es-discuss at mozilla.org > >> https://mail.mozilla.org/listinfo/es-discuss > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180323/22db27d7/attachment.html>
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).
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 <naveen.chwl at gmail.com> 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 <isiahmeadows at gmail.com <mailto:isiahmeadows at gmail.com>> 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 > me at isiahmeadows.com <mailto:me at isiahmeadows.com> > > Looking for web consulting? Or a new website? > Send me an email and we can get started. > www.isiahmeadows.com <http://www.isiahmeadows.com/> > > > On Thu, Mar 22, 2018 at 12:23 PM, Michael Luder-Rosefield > <rosyatrandom at gmail.com <mailto:rosyatrandom at gmail.com>> wrote: > > That strikes me as territory the 'do expression' proposal > > https://github.com/tc39/proposal-do-expressions <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 <mikesamuel at gmail.com <mailto:mikesamuel at gmail.com>> wrote: > >> > >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <isiahmeadows at gmail.com <mailto:isiahmeadows at gmail.com>> > >> 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 > >>> me at isiahmeadows.com <mailto:me at isiahmeadows.com> > >>> > >>> Looking for web consulting? Or a new website? > >>> Send me an email and we can get started. > >>> www.isiahmeadows.com <http://www.isiahmeadows.com/> > >>> > >>> > >>> On Thu, Mar 22, 2018 at 3:21 AM, Rodrigo <rodrigolive at gmail.com <mailto:rodrigolive at gmail.com>> 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 <mikesamuel at gmail.com <mailto:mikesamuel at gmail.com>> > >>> > escribió: > >>> >> > >>> >> > >>> >> > >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton > >>> >> <sebastian at malton.name <mailto:sebastian at malton.name>> > >>> >> 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 > >>> >> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> > >>> >> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> > >>> > > >>> > > >>> > _______________________________________________ > >>> > es-discuss mailing list > >>> > es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> > >>> > https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> > >>> > > >> > >> _______________________________________________ > >> es-discuss mailing list > >> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> > >> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> > https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180323/afcc8f61/attachment-0001.html>
@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 theif
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).
# realworld example, hard to find variable declaration:
$redis->subscribe( 'queue', my $callback = sub {
...
});
@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 <naveen.chwl at gmail.com> 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 <isiahmeadows at gmail.com> 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 >> me at isiahmeadows.com >> >> 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 >> <rosyatrandom at gmail.com> 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 <mikesamuel at gmail.com> wrote: >> >> >> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows <isiahmeadows at gmail.com> >> >> 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 >> >>> me at isiahmeadows.com >> >>> >> >>> 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 <rodrigolive at gmail.com> >> >>> 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 <mikesamuel at gmail.com> >> >>> > escribió: >> >>> >> >> >>> >> >> >>> >> >> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton >> >>> >> <sebastian at malton.name> >> >>> >> 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 >> >>> >> es-discuss at mozilla.org >> >>> >> https://mail.mozilla.org/listinfo/es-discuss >> >>> > >> >>> > >> >>> > _______________________________________________ >> >>> > es-discuss mailing list >> >>> > es-discuss at mozilla.org >> >>> > https://mail.mozilla.org/listinfo/es-discuss >> >>> > >> >> >> >> _______________________________________________ >> >> es-discuss mailing list >> >> es-discuss at mozilla.org >> >> https://mail.mozilla.org/listinfo/es-discuss >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss >
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!
foo(const x = 10)
bar(x)
vs
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.
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 <rodrigolive at gmail.com> 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 <naveen.chwl at gmail.com> > 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 <isiahmeadows at gmail.com> > 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 > >> me at isiahmeadows.com > >> > >> 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 > >> <rosyatrandom at gmail.com> 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 <mikesamuel at gmail.com> > wrote: > >> >> > >> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows < > isiahmeadows at gmail.com> > >> >> 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 > >> >>> me at isiahmeadows.com > >> >>> > >> >>> 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 <rodrigolive at gmail.com> > >> >>> 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 <mikesamuel at gmail.com> > >> >>> > escribió: > >> >>> >> > >> >>> >> > >> >>> >> > >> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton > >> >>> >> <sebastian at malton.name> > >> >>> >> 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 > >> >>> >> es-discuss at mozilla.org > >> >>> >> https://mail.mozilla.org/listinfo/es-discuss > >> >>> > > >> >>> > > >> >>> > _______________________________________________ > >> >>> > es-discuss mailing list > >> >>> > es-discuss at mozilla.org > >> >>> > https://mail.mozilla.org/listinfo/es-discuss > >> >>> > > >> >> > >> >> _______________________________________________ > >> >> es-discuss mailing list > >> >> es-discuss at mozilla.org > >> >> https://mail.mozilla.org/listinfo/es-discuss > >> _______________________________________________ > >> es-discuss mailing list > >> es-discuss at mozilla.org > >> https://mail.mozilla.org/listinfo/es-discuss > > > > > > _______________________________________________ > > es-discuss mailing list > > es-discuss at mozilla.org > > https://mail.mozilla.org/listinfo/es-discuss > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180324/5c078f54/attachment-0001.html>
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 me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
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 me at isiahmeadows.com 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 <naveen.chwl at gmail.com> 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 <rodrigolive at gmail.com> 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 <naveen.chwl at gmail.com> >> 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 <isiahmeadows at gmail.com> >> > 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 >> >> me at isiahmeadows.com >> >> >> >> 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 >> >> <rosyatrandom at gmail.com> 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 <mikesamuel at gmail.com> >> >> > wrote: >> >> >> >> >> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows >> >> >> <isiahmeadows at gmail.com> >> >> >> 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 >> >> >>> me at isiahmeadows.com >> >> >>> >> >> >>> 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 <rodrigolive at gmail.com> >> >> >>> 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 <mikesamuel at gmail.com> >> >> >>> > escribió: >> >> >>> >> >> >> >>> >> >> >> >>> >> >> >> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton >> >> >>> >> <sebastian at malton.name> >> >> >>> >> 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 >> >> >>> >> es-discuss at mozilla.org >> >> >>> >> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> > >> >> >>> > >> >> >>> > _______________________________________________ >> >> >>> > es-discuss mailing list >> >> >>> > es-discuss at mozilla.org >> >> >>> > https://mail.mozilla.org/listinfo/es-discuss >> >> >>> > >> >> >> >> >> >> _______________________________________________ >> >> >> es-discuss mailing list >> >> >> es-discuss at mozilla.org >> >> >> https://mail.mozilla.org/listinfo/es-discuss >> >> _______________________________________________ >> >> es-discuss mailing list >> >> es-discuss at mozilla.org >> >> https://mail.mozilla.org/listinfo/es-discuss >> > >> > >> > _______________________________________________ >> > es-discuss mailing list >> > es-discuss at mozilla.org >> > https://mail.mozilla.org/listinfo/es-discuss >> >
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?
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 <isiahmeadows at gmail.com> 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 > me at isiahmeadows.com > > 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 <naveen.chwl at gmail.com> > 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 <rodrigolive at gmail.com> 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 <naveen.chwl at gmail.com> > >> 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 <isiahmeadows at gmail.com> > >> > 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 > >> >> me at isiahmeadows.com > >> >> > >> >> 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 > >> >> <rosyatrandom at gmail.com> 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 <mikesamuel at gmail.com> > >> >> > wrote: > >> >> >> > >> >> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows > >> >> >> <isiahmeadows at gmail.com> > >> >> >> 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 > >> >> >>> me at isiahmeadows.com > >> >> >>> > >> >> >>> 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 <rodrigolive at gmail.com> > >> >> >>> 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 <mikesamuel at gmail.com > > > >> >> >>> > escribió: > >> >> >>> >> > >> >> >>> >> > >> >> >>> >> > >> >> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton > >> >> >>> >> <sebastian at malton.name> > >> >> >>> >> 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 > >> >> >>> >> es-discuss at mozilla.org > >> >> >>> >> https://mail.mozilla.org/listinfo/es-discuss > >> >> >>> > > >> >> >>> > > >> >> >>> > _______________________________________________ > >> >> >>> > es-discuss mailing list > >> >> >>> > es-discuss at mozilla.org > >> >> >>> > https://mail.mozilla.org/listinfo/es-discuss > >> >> >>> > > >> >> >> > >> >> >> _______________________________________________ > >> >> >> es-discuss mailing list > >> >> >> es-discuss at mozilla.org > >> >> >> https://mail.mozilla.org/listinfo/es-discuss > >> >> _______________________________________________ > >> >> es-discuss mailing list > >> >> es-discuss at mozilla.org > >> >> https://mail.mozilla.org/listinfo/es-discuss > >> > > >> > > >> > _______________________________________________ > >> > es-discuss mailing list > >> > es-discuss at mozilla.org > >> > https://mail.mozilla.org/listinfo/es-discuss > >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180325/2a5f55cb/attachment-0001.html>
- My concern with
while
is that it's a little too duplicative of C-stylefor
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). - 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 me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
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 me at isiahmeadows.com 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 <naveen.chwl at gmail.com> 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 <isiahmeadows at gmail.com> 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 >> me at isiahmeadows.com >> >> 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 <naveen.chwl at gmail.com> >> 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 <rodrigolive at gmail.com> 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 <naveen.chwl at gmail.com> >> >> 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 <isiahmeadows at gmail.com> >> >> > 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 >> >> >> me at isiahmeadows.com >> >> >> >> >> >> 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 >> >> >> <rosyatrandom at gmail.com> 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 <mikesamuel at gmail.com> >> >> >> > wrote: >> >> >> >> >> >> >> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows >> >> >> >> <isiahmeadows at gmail.com> >> >> >> >> 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 >> >> >> >>> me at isiahmeadows.com >> >> >> >>> >> >> >> >>> 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 <rodrigolive at gmail.com> >> >> >> >>> 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 >> >> >> >>> > <mikesamuel at gmail.com> >> >> >> >>> > escribió: >> >> >> >>> >> >> >> >> >>> >> >> >> >> >>> >> >> >> >> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton >> >> >> >>> >> <sebastian at malton.name> >> >> >> >>> >> 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 >> >> >> >>> >> es-discuss at mozilla.org >> >> >> >>> >> https://mail.mozilla.org/listinfo/es-discuss >> >> >> >>> > >> >> >> >>> > >> >> >> >>> > _______________________________________________ >> >> >> >>> > es-discuss mailing list >> >> >> >>> > es-discuss at mozilla.org >> >> >> >>> > https://mail.mozilla.org/listinfo/es-discuss >> >> >> >>> > >> >> >> >> >> >> >> >> _______________________________________________ >> >> >> >> es-discuss mailing list >> >> >> >> es-discuss at mozilla.org >> >> >> >> https://mail.mozilla.org/listinfo/es-discuss >> >> >> _______________________________________________ >> >> >> es-discuss mailing list >> >> >> es-discuss at mozilla.org >> >> >> https://mail.mozilla.org/listinfo/es-discuss >> >> > >> >> > >> >> > _______________________________________________ >> >> > es-discuss mailing list >> >> > es-discuss at mozilla.org >> >> > https://mail.mozilla.org/listinfo/es-discuss >> >> >
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).
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 <isiahmeadows at gmail.com> 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 > me at isiahmeadows.com > > 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 <naveen.chwl at gmail.com> > 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 <isiahmeadows at gmail.com> > 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 > >> me at isiahmeadows.com > >> > >> 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 <naveen.chwl at gmail.com> > >> 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 <rodrigolive at gmail.com> 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 < > naveen.chwl at gmail.com> > >> >> 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 <isiahmeadows at gmail.com > > > >> >> > 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 > >> >> >> me at isiahmeadows.com > >> >> >> > >> >> >> 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 > >> >> >> <rosyatrandom at gmail.com> 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 <mikesamuel at gmail.com> > >> >> >> > wrote: > >> >> >> >> > >> >> >> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows > >> >> >> >> <isiahmeadows at gmail.com> > >> >> >> >> 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 > >> >> >> >>> me at isiahmeadows.com > >> >> >> >>> > >> >> >> >>> 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 < > rodrigolive at gmail.com> > >> >> >> >>> 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 > >> >> >> >>> > <mikesamuel at gmail.com> > >> >> >> >>> > escribió: > >> >> >> >>> >> > >> >> >> >>> >> > >> >> >> >>> >> > >> >> >> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton > >> >> >> >>> >> <sebastian at malton.name> > >> >> >> >>> >> 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 > >> >> >> >>> >> es-discuss at mozilla.org > >> >> >> >>> >> https://mail.mozilla.org/listinfo/es-discuss > >> >> >> >>> > > >> >> >> >>> > > >> >> >> >>> > _______________________________________________ > >> >> >> >>> > es-discuss mailing list > >> >> >> >>> > es-discuss at mozilla.org > >> >> >> >>> > https://mail.mozilla.org/listinfo/es-discuss > >> >> >> >>> > > >> >> >> >> > >> >> >> >> _______________________________________________ > >> >> >> >> es-discuss mailing list > >> >> >> >> es-discuss at mozilla.org > >> >> >> >> https://mail.mozilla.org/listinfo/es-discuss > >> >> >> _______________________________________________ > >> >> >> es-discuss mailing list > >> >> >> es-discuss at mozilla.org > >> >> >> https://mail.mozilla.org/listinfo/es-discuss > >> >> > > >> >> > > >> >> > _______________________________________________ > >> >> > es-discuss mailing list > >> >> > es-discuss at mozilla.org > >> >> > https://mail.mozilla.org/listinfo/es-discuss > >> >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180325/ea4597fc/attachment-0001.html>
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 me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
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 me at isiahmeadows.com 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 <naveen.chwl at gmail.com> 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 <isiahmeadows at gmail.com> 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 >> me at isiahmeadows.com >> >> 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 <naveen.chwl at gmail.com> >> 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 <isiahmeadows at gmail.com> >> > 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 >> >> me at isiahmeadows.com >> >> >> >> 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 <naveen.chwl at gmail.com> >> >> 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 <rodrigolive at gmail.com> 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 >> >> >> <naveen.chwl at gmail.com> >> >> >> 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 >> >> >> > <isiahmeadows at gmail.com> >> >> >> > 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 >> >> >> >> me at isiahmeadows.com >> >> >> >> >> >> >> >> 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 >> >> >> >> <rosyatrandom at gmail.com> 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 <mikesamuel at gmail.com> >> >> >> >> > wrote: >> >> >> >> >> >> >> >> >> >> On Thu, Mar 22, 2018 at 3:50 AM, Isiah Meadows >> >> >> >> >> <isiahmeadows at gmail.com> >> >> >> >> >> 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 >> >> >> >> >>> me at isiahmeadows.com >> >> >> >> >>> >> >> >> >> >>> 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 >> >> >> >> >>> <rodrigolive at gmail.com> >> >> >> >> >>> 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 >> >> >> >> >>> > <mikesamuel at gmail.com> >> >> >> >> >>> > escribió: >> >> >> >> >>> >> >> >> >> >> >>> >> >> >> >> >> >>> >> >> >> >> >> >>> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton >> >> >> >> >>> >> <sebastian at malton.name> >> >> >> >> >>> >> 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 >> >> >> >> >>> >> es-discuss at mozilla.org >> >> >> >> >>> >> https://mail.mozilla.org/listinfo/es-discuss >> >> >> >> >>> > >> >> >> >> >>> > >> >> >> >> >>> > _______________________________________________ >> >> >> >> >>> > es-discuss mailing list >> >> >> >> >>> > es-discuss at mozilla.org >> >> >> >> >>> > https://mail.mozilla.org/listinfo/es-discuss >> >> >> >> >>> > >> >> >> >> >> >> >> >> >> >> _______________________________________________ >> >> >> >> >> es-discuss mailing list >> >> >> >> >> es-discuss at mozilla.org >> >> >> >> >> https://mail.mozilla.org/listinfo/es-discuss >> >> >> >> _______________________________________________ >> >> >> >> es-discuss mailing list >> >> >> >> es-discuss at mozilla.org >> >> >> >> https://mail.mozilla.org/listinfo/es-discuss >> >> >> > >> >> >> > >> >> >> > _______________________________________________ >> >> >> > es-discuss mailing list >> >> >> > es-discuss at mozilla.org >> >> >> > https://mail.mozilla.org/listinfo/es-discuss >> >> >> >
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:
let foo = getFoo()
if (foo.isReady()) {
foo.start()
} else {
foo.wait()
}
Isiah Meadows me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
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 me at isiahmeadows.com 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 <nison.mael at gmail.com> 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 <isiahmeadows at gmail.com> wrote: >> >> My implication was that it'd only be available in the `if` (if >> declared with `let`/`const`). >> ----- >> >> Isiah Meadows >> me at isiahmeadows.com >> >> 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 <sebastian at malton.name> >> 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: isiahmeadows at gmail.com >> > Sent: March 21, 2018 6:18 PM >> > To: mikesamuel at gmail.com >> > Cc: sebastian at malton.name; es-discuss at mozilla.org >> > 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 >> > me at isiahmeadows.com >> > >> > 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 <mikesamuel at gmail.com> >> > wrote: >> >> >> >> >> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton >> >> <sebastian at malton.name> >> >> 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 >> >> es-discuss at mozilla.org >> >> https://mail.mozilla.org/listinfo/es-discuss >> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss
I don't get it. Please give an example of the per-iteration initialization
in the while loop... (the for-loop version before ;
does it before
iteration, not per-iteration)
I don't get it. Please give an example of the per-iteration initialization in the while loop... (the for-loop version before `;` does it before iteration, not per-iteration) On Mon, 26 Mar 2018 at 07:20 Isiah Meadows <isiahmeadows at gmail.com> wrote: > 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 > me at isiahmeadows.com > > 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 <nison.mael at gmail.com> 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 <isiahmeadows at gmail.com> > wrote: > >> > >> My implication was that it'd only be available in the `if` (if > >> declared with `let`/`const`). > >> ----- > >> > >> Isiah Meadows > >> me at isiahmeadows.com > >> > >> 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 < > sebastian at malton.name> > >> 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: isiahmeadows at gmail.com > >> > Sent: March 21, 2018 6:18 PM > >> > To: mikesamuel at gmail.com > >> > Cc: sebastian at malton.name; es-discuss at mozilla.org > >> > 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 > >> > me at isiahmeadows.com > >> > > >> > 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 <mikesamuel at gmail.com> > >> > wrote: > >> >> > >> >> > >> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton > >> >> <sebastian at malton.name> > >> >> 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 > >> >> es-discuss at mozilla.org > >> >> https://mail.mozilla.org/listinfo/es-discuss > >> >> > >> _______________________________________________ > >> es-discuss mailing list > >> es-discuss at mozilla.org > >> https://mail.mozilla.org/listinfo/es-discuss > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180326/fc252f3d/attachment-0001.html>
Maybe this analogue to the for (const ... of ...)
:
function keyList(map) {
const list = new Array(map.size)
const iter = map.keys()
while (const {done, value} = iter.next(); !done) {
list.push(value)
}
return list
}
But in general, the more I've thought about it, the more I've noticed
it doesn't generalize well past the C-style for
loop and I find
myself getting ready to reinvent an awkward minor variant of it
repeatedly. And without anything to the tune of pattern matching
(which Rust has) or a loop
/recur
-like while
-ish loop (which is
what Clojure uses instead), it just seems pointless.
Isiah Meadows me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
Maybe this analogue to the `for (const ... of ...)`: ```js function keyList(map) { const list = new Array(map.size) const iter = map.keys() while (const {done, value} = iter.next(); !done) { list.push(value) } return list } ``` But in general, the more I've thought about it, the more I've noticed it doesn't generalize well past the C-style `for` loop and I find myself getting ready to reinvent an awkward minor variant of it repeatedly. And without anything to the tune of pattern matching (which Rust has) or a `loop`/`recur`-like `while`-ish loop (which is what Clojure uses instead), it just seems pointless. ----- Isiah Meadows me at isiahmeadows.com Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com On Mon, Mar 26, 2018 at 2:33 AM, Naveen Chawla <naveen.chwl at gmail.com> wrote: > I don't get it. Please give an example of the per-iteration initialization > in the while loop... (the for-loop version before `;` does it before > iteration, not per-iteration) > > On Mon, 26 Mar 2018 at 07:20 Isiah Meadows <isiahmeadows at gmail.com> wrote: >> >> 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 >> me at isiahmeadows.com >> >> 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 <nison.mael at gmail.com> 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 <isiahmeadows at gmail.com> >> > wrote: >> >> >> >> My implication was that it'd only be available in the `if` (if >> >> declared with `let`/`const`). >> >> ----- >> >> >> >> Isiah Meadows >> >> me at isiahmeadows.com >> >> >> >> 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 >> >> <sebastian at malton.name> >> >> 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: isiahmeadows at gmail.com >> >> > Sent: March 21, 2018 6:18 PM >> >> > To: mikesamuel at gmail.com >> >> > Cc: sebastian at malton.name; es-discuss at mozilla.org >> >> > 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 >> >> > me at isiahmeadows.com >> >> > >> >> > 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 <mikesamuel at gmail.com> >> >> > wrote: >> >> >> >> >> >> >> >> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton >> >> >> <sebastian at malton.name> >> >> >> 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 >> >> >> es-discuss at mozilla.org >> >> >> https://mail.mozilla.org/listinfo/es-discuss >> >> >> >> >> _______________________________________________ >> >> es-discuss mailing list >> >> es-discuss at mozilla.org >> >> https://mail.mozilla.org/listinfo/es-discuss >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss
OK, but your example wouldn't be acceptable in JavaScript, because it's
inconsistent with how for(;;)
does initialization before the first ;
,
which is before iteration.
That's why I was saying that initializers-as-expressions simplifies doing things like that, despite the other concerns.
OK, but your example wouldn't be acceptable in JavaScript, because it's inconsistent with how `for(;;)` does initialization before the first `;`, which is before iteration. That's why I was saying that initializers-as-expressions simplifies doing things like that, despite the other concerns. On Mon, 26 Mar 2018 at 12:18 Isiah Meadows <isiahmeadows at gmail.com> wrote: > Maybe this analogue to the `for (const ... of ...)`: > > ```js > function keyList(map) { > const list = new Array(map.size) > const iter = map.keys() > > while (const {done, value} = iter.next(); !done) { > list.push(value) > } > > return list > } > ``` > > But in general, the more I've thought about it, the more I've noticed > it doesn't generalize well past the C-style `for` loop and I find > myself getting ready to reinvent an awkward minor variant of it > repeatedly. And without anything to the tune of pattern matching > (which Rust has) or a `loop`/`recur`-like `while`-ish loop (which is > what Clojure uses instead), it just seems pointless. > > ----- > > Isiah Meadows > me at isiahmeadows.com > > Looking for web consulting? Or a new website? > Send me an email and we can get started. > www.isiahmeadows.com > > > On Mon, Mar 26, 2018 at 2:33 AM, Naveen Chawla <naveen.chwl at gmail.com> > wrote: > > I don't get it. Please give an example of the per-iteration > initialization > > in the while loop... (the for-loop version before `;` does it before > > iteration, not per-iteration) > > > > On Mon, 26 Mar 2018 at 07:20 Isiah Meadows <isiahmeadows at gmail.com> > wrote: > >> > >> 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 > >> me at isiahmeadows.com > >> > >> 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 <nison.mael at gmail.com> > 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 <isiahmeadows at gmail.com> > >> > wrote: > >> >> > >> >> My implication was that it'd only be available in the `if` (if > >> >> declared with `let`/`const`). > >> >> ----- > >> >> > >> >> Isiah Meadows > >> >> me at isiahmeadows.com > >> >> > >> >> 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 > >> >> <sebastian at malton.name> > >> >> 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: isiahmeadows at gmail.com > >> >> > Sent: March 21, 2018 6:18 PM > >> >> > To: mikesamuel at gmail.com > >> >> > Cc: sebastian at malton.name; es-discuss at mozilla.org > >> >> > 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 > >> >> > me at isiahmeadows.com > >> >> > > >> >> > 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 <mikesamuel at gmail.com > > > >> >> > wrote: > >> >> >> > >> >> >> > >> >> >> On Wed, Mar 21, 2018 at 1:27 PM, Sebastian Malton > >> >> >> <sebastian at malton.name> > >> >> >> 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 > >> >> >> es-discuss at mozilla.org > >> >> >> https://mail.mozilla.org/listinfo/es-discuss > >> >> >> > >> >> _______________________________________________ > >> >> es-discuss mailing list > >> >> es-discuss at mozilla.org > >> >> https://mail.mozilla.org/listinfo/es-discuss > >> _______________________________________________ > >> es-discuss mailing list > >> es-discuss at mozilla.org > >> https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180326/d0e7c7ca/attachment-0001.html>
On 03/22/2018 11:21 PM, Naveen Chawla 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.
Yes, I think there is a compelling case for not allowing const
/ let
declarations to be evaluated as expressions.
As was noted,
if(x = 5)
is already allowed.Is
if(const x = 5)
really that much of a stretch?
That's fine in this case, and I happily use this construct in C++.
But that's very different from allowing const
/ let
declarations anyplace you allow an expression.
To answer a concern about a function call like
myFunction(const x = 7)
, of course the scope ofx
would be where it is declared.
And here we come the problem: the scope.
It can't be anywhere else (like inside myFunction or something).
We wouldn't want to repeat the var hoisting problems, so the scope of a general subexpression declaration would need to be the subexpression in which it's contained and not some outer context. If you don't do that, you'll eventually run into the same problems as with var.
However, that's not what the current uses of such declarations do. For example,
for (var i = expr; ...) {...}
scopes i to the body of the loop, and you get a new i binding for each iteration, which is important for lambda capture, even though expr is evaluated only once. Subexpression scoping would be incompatible with that.
As such, we can reasonably allow const
/ let
declarations in other specific contexts such as at the top level of if statement condition expressions, but not in subexpressions in general.
Waldemar
On 03/22/2018 11:21 PM, Naveen Chawla 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. Yes, I think there is a compelling case for not allowing `const` / `let` declarations to be evaluated as expressions. > As was noted, > > `if(x = 5)` is already allowed. > > Is `if(const x = 5)` really that much of a stretch? That's fine in this case, and I happily use this construct in C++. But that's *very* different from allowing `const` / `let` declarations anyplace you allow an expression. > 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. And here we come the problem: the scope. > It can't be anywhere else (like inside myFunction or something). We wouldn't want to repeat the var hoisting problems, so the scope of a general subexpression declaration would need to be the subexpression in which it's contained and not some outer context. If you don't do that, you'll eventually run into the same problems as with var. However, that's not what the current uses of such declarations do. For example, for (var i = expr; ...) {...} scopes i to the body of the loop, and you get a new i binding for each iteration, which is important for lambda capture, even though expr is evaluated only once. Subexpression scoping would be incompatible with that. As such, we can reasonably allow `const` / `let` declarations in other specific contexts such as at the top level of if statement condition expressions, but not in subexpressions in general. Waldemar
Same sentiments, and I am pleased with how golang handles this common
desire. Another idea I had is a for
statement with only one expression of
declarations, or even a new use for the dead with
statement (conveniently
named).
Same sentiments, and I am pleased with how golang handles this common desire. Another idea I had is a `for` statement with only one expression of declarations, or even a new use for the dead `with` statement (conveniently named). On Tue, Mar 20, 2018 at 3:57 PM, Rodrigo <rodrigolive at gmail.com> wrote: > Proposal: inline let/const statements to declare and initialize > variables within if statements, so that temporary variables exist only > within the if/else block scope. > > Reason: limits variable scope to the block where really needed, in > similar fashion to variables defined in for(;;) statements. This > improves readability while reducing unnecessary variables roaming > outside their needed block. > > The syntax would be very similar to the for(;;) assignment/test pair: > > if (let x = 100; x > 50) { > console.log(x); // 100 > } > console.log(x); // ReferenceError > > // same for const > if( const x = foo(); typeof x === 'object' ) { > //... > } > > // the variable is available within any else block > // after its declaration > if (let x = foo(); x < 50) { > console.log(x); // y is not available here > } else if (let y = bar(); y > 0) { > console.log(x, y); > } else { > console.log(x, y); > } > > Right now there isn't a way to limit a variable to the if block: > > let x = 100; > if (x > 50) { > console.log(x); > } > // x is in scope, but may not be needed beyond the if statement > console.log(x); > > // or a non-strict assignment, which also "leaks" scope > if( (x = 100) > 50 ) { > // ... > } > > There are many "workarounds" available, here's a few: > > // workaround 1: can be remedied with a scope block > // but it's asymmetrical and non-idiomatic > { > let x = 100; > if (x > 50) { > console.log(x); > } > } > > // workaround 2: with a for statement > // but this is non-idiomatic, hard to read and error-prone > for (let x = 100; x > 50;) { > console.log(x); > break; > } > > If-initialization is available in many languages (Go, Perl and Ruby > come to mind) and are considered best practice in each one of them: > > // Golang - x is defined, assigned and conditionally tested > if x := 100; x > 50 { > // x is in scope here > } else { > // and in here > } > // x is not available here > > ###### Perl > if( my $x = 100 ) { > print $x; > } > print $x; # an error > > if ( ( my $x = myfoo() ) > 50 ) { # also ok in Perl > print $x; > } > > ###### Ruby > if ( x = 100 ) # parens required per style guide > puts(x) > end > puts(x) # unfortunately Ruby does not limit scope to if, so x "leaks" > > I think this would be a great and important addition to the language. > > -Rodrigo > > PS: Just for the sake of comparison, Perl-style if-assignments could also > be an > option, albeit a very bad one IMO: > > if( ( let x = 100 ) > 50 ) { > } > > A Perl-style, value-returning let/const has readability issues, opens > quite a few fronts and sort of implies that let/const can return > values anywhere in the code outside if/else. On the other hand it > would fit with the currently if assignment if( x = y ). Definitely not > recommended. > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180407/8906a855/attachment.html>
Proposal: inline let/const statements to declare and initialize variables within if statements, so that temporary variables exist only within the if/else block scope.
Reason: limits variable scope to the block where really needed, in similar fashion to variables defined in for(;;) statements. This improves readability while reducing unnecessary variables roaming outside their needed block.
The syntax would be very similar to the for(;;) assignment/test pair:
Right now there isn't a way to limit a variable to the if block:
There are many "workarounds" available, here's a few:
If-initialization is available in many languages (Go, Perl and Ruby come to mind) and are considered best practice in each one of them:
I think this would be a great and important addition to the language.
-Rodrigo
PS: Just for the sake of comparison, Perl-style if-assignments could also be an option, albeit a very bad one IMO:
A Perl-style, value-returning let/const has readability issues, opens quite a few fronts and sort of implies that let/const can return values anywhere in the code outside if/else. On the other hand it would fit with the currently if assignment if( x = y ). Definitely not recommended.