Proposal: anaphoric if and while syntax
An alternative to the block which you ended up with is to extract that logic to a function, which provides something which can be tested too. Possibly overkill for oneliners like this though.
However, writing a lot of code like this myself (get a value, if it's truthy do something, else do other), that's a nice idea for an extension that doesn't add extra variable bindings to the containing scope.
Does this really need new semantic interpretation of the syntax? Using the
Array.prototype
methods .forEach
and .map
already mitigates this
problem as far as I can tell by having a different bound variable (argument
in this case) for each call.
I agree that the behavior may be non-intuitive if you have a background coming from Java or C++ but the implications would be quite far-reaching and the backward compatibility with previous versions would be difficult to handle. Wouldn't this require a new 'use strict'-like mode?
On 14 September 2016 at 17:58:24, Viktor Kronvall (viktor.kronvall at gmail.com(mailto:viktor.kronvall at gmail.com)) wrote:
Does this really need new semantic interpretation of the syntax? Using the
Array.prototype
methods.forEach
and.map
already mitigates this problem as far as I can tell by having a different bound variable (argument in this case) for each call.I agree that the behavior may be non-intuitive if you have a background coming from Java or C++ but the implications would be quite far-reaching and the backward compatibility with previous versions would be difficult to handle. Wouldn't this require a new 'use strict'-like mode?
No, adding anaphoric if as I have described it will require neither
new semantic interpretation of the syntax nor a new strictness
directive. Currently, it is a syntax error to write a variable
declaration within an if
or while
condition, so there is no valid
code which contains the proposed syntax.
Also note that under this proposal, declarations made using the var
keyword would still be hoisted to function scope, not scoped to the
body associated with the condition - i.e., there would be no semantic
difference whatsoever between the following two snippets:
if (var stuff = some.cool(expression)) doThings(stuff);
// equivalent to
var stuff;
if (stuff = some.cool(expression)) doThings(stuff);
Only declarations made with the newer let
and const
keywords,
which are never hoisted to function scope anyway, would be narrowly
scoped to the condition and its body.
if (let stuff = expr) doThings(stuff);
// equivalent to
{
let stuff = expr;
if (stuff) doThings(stuff);
}
(An aside: as the last example demonstrates, the if
or while
statement body should not need braces to isolate the scope in this
way. This is consistent with the current behaviour for declarations in
loops.)
While I like the idea of making it simpler to restrict the scope of
variables, currently a reigning best practice is to never do assignment in
conditionals, since it can be an easy typo from ==
or ===
, and because
it conflates assignment with expression truthiness, harming readability.
This seems like it runs afoul of the latter, certainly, and I haven't yet convinced myself whether it creates typo hazards (I'm thinking no, but wanted to bring it up just in case).
On Sep 14, 2016, at 6:41 PM, Jordan Harband <ljharb at gmail.com> wrote:
While I like the idea of making it simpler to restrict the scope of variables, currently a reigning best practice is to never do assignment in conditionals, since it can be an easy typo from
==
or===
, and because it conflates assignment with expression truthiness, harming readability.This seems like it runs afoul of the latter, certainly, and I haven't yet convinced myself whether it creates typo hazards (I'm thinking no, but wanted to bring it up just in case).
Given that let x == 10
or let x === 10
is illegal, it doesn’t seem too bad to allow if (let x = f(y))
, LexicalDeclaration is visually distinct from EqualityExpression because of the let
or const
prefix.
I like this proposal. Specially for while
loops.
When I want to iterate all matches of a global regex, I always think the variable declaration at the top seems ugly
let match;
while (match = regex.exec(string)) {
// ...
}
This looks better:
while (let match = regex.exec(string)) {
// ...
}
For what it's worth, that specific use case would be addressed by tc39/String.prototype.matchAll ;-)
Danielle McLean wrote:
variables declared using
let
orconst
would be scoped to the individualif
orwhile
statement, rather than the containing block. In other words, the above syntax would be equivalent to the following currently-valid form I ended up writing:{ const oldValue = _.get(object, 'some.long.path'); if (oldValue) object.some.long.path = transform(oldValue); }
What about else
blocks, would the variables be available in them as well?
What about else if
?
"Bergi" <a.d.bergi at web.de> wrote:
What about
else
blocks, would the variables be available in them as well?
No. If the else
block executes, then the variable's value would be
falsy and therefore presumably not useful for further processing. Of
course, there are multiple falsy values in ES, but knowing which
specific falsy value a condition produced is far less useful than
knowing which specific truthy value a condition produced.
If you've got a use case for the variable's scope extending into the
else
block, though, feel free to change this. ;)
"Alan Johnson" <alan at breakrs.com> wrote:
What about
else if
?
As with a standalone else
, the else if
branches are only reached
if the value from the if
branch was falsy and therefore presumably
not useful. So, again, the variable from the original if
condition
need not be available.
It should however be possible to declare another variable in an
else if
's condition, for consistency. Like this:
if (const x = expr()) {
// use x
} else if (const x = expr2()) {
// use x in a different way
} else {
// couldn't get either kind of x :(
}
For what it's worth, I'm on the side of people that do not want to see assignment statements in control structures. I don't think it is necessary and it results in code that is harder to read.
How so? Assignment is already possible in control structures. I think this reads better:
if (let a = foo) {
Than:
let a;
//...
if (a = foo) {
Having the let
or const
inside the conditional part clarifies the
intent. There's an argument for not doing assignment inside the conditional
part, but it's subjective and people will write code that way regardless.
I'd much rather see let
or const
next to code like that if it means
mistakes are less likely to be made.
I really like the idea of declaring a variable directly in the conditional itself. Many other languages do it. It's certainly not a critical thing (it makes 2 lines of code into 1) but I certainly would like it to happen. Considering it only moves the declaration I'm not convinced it makes code harder to read; in fact since you are explicitly saying it's part of the conditional you're declaring it in I feel like that makes it more clear as there is no longer a risk of someone re-using that variable outside of, say, the while loop it's declared in (which is what can happen today).
I know we don't have voting but this sure has my vote. I'd love to see it championed at an upcoming meeting.
The main barrier that I can see is that this requires new semantics. At the moment, variable declarations don't have any kind of usable result. If you consider
let a = eval('let b = 1');
console.log(a);
//-> undefined
This sounds like an easy thing to solve, but how about this:
if (let a = foo(), b = bar()) {
}
Does the block execute if a
and b
are both truthy, or just b
? My gut
instinct says "if bar() is truthy", but it still seems awkward. Any option
might be confusing depending on your level of experience. What about this:
if (let { a, b } = foo) {
}
Does the block execute if a
and b
are both truthy, just b
, or if
foo
is truthy? I'd lean towards foo
in this case, but I think it looks
pretty bad and I'd hate to see it in code. It might make more sense to
throw for destructuring or if there's more than one assignment.
I agree but at the same time those examples simply look like bad coding practices to me and we can't completely hide from those. Since it's new semantics we shouldn't have to worry about it breaking something existing and it would be really easy to do a transpile back into ES5 or ES6 should people want to use it ahead of time.
Just my 2 cents. You certainly have valid points. The only awkward thing, in my opinion, is if we're using let and const we're going to have to allow var as well (it would be odd that, in a single place, you can use let and const but not var). Not sure how var should be really handled here; probably allow it but make it a bad practice to use var in this type of declaration. In my opinion anyway.
On 09/12/2016 05:32 PM, Danielle McLean wrote:
In current ECMAScript, it is legal to place a variable declaration inside the initialiser of a
for
loop, as well as to declare the variable used by afor...in
orfor...of
loop within the declaring expression:for (let i = 0; i < 5; ++i) console.log(i); for (let item of collection) process(item);
When this syntax is used with
let
orconst
, the resulting variable is scoped to the loop and is not visible to the rest of the surrounding block.I propose that this syntax be extended, making it legal to place a variable declaration within the condition of an
if
orwhile
statement. Any truthy value will cause theif
block to run orwhile
loop to repeat, as usual - the advantage is that the particular truthy value is bound to a variable and can be used inside the conditional block.
My initial reaction was positive, but now I don't think it works.
First, other places in the grammar do not restrict let/const to a single variable. Should
if (let a=0, b=1, c=0) { ... }
execute the if block or not? The obvious solution is to require a single variable, which means the grammar for these let/consts is different from others. What about
x = { a: 1 };
if (let {a} = x) { ... }
Second, that previous example makes it unclear to me at first glance what the intended semantics should be. I could imagine this printing either 1 or 2:
h = { foo: 0};
if (let {bar=1} = h) {
print(1);
} else {
print(2);
}
Is the conditional based on the variable's final value, or on whether or not the destructuring found a match? I could argue for either one, so even if there's a natural way to resolve my first problem, I think the code looks ambiguous to the eye.
if (let { children } = node) {
print("interior node");
} else {
print("leaf node");
}
Again, the simplest way to resolve this is to restrict it to "let/const IDENTIFIER = expression", but it feels weird to have different rules for this particular case. for(let...) on the other hand, does not attempt to use the let expression as a value, so it does not encounter any of these problems.
As a minor issue, it also feels a little awkward to special-case this conditional expression. I can do
if (let x = foo()) print(x)
but not
(let x = foo()) && print(x)
Why not more generally - allow let/var declarations in expressions?
coming from a long and rich C background, I have no issues with the existing mechanisms... but for those languages that do support variable declarations in for loops; I've always wondered why not any expression?
if( let a = ( let b = 10 ) * 3 > 10 )
... or ...
c = (let a = b*d)
granted, the scope is extremely limited in the last case...
if( let a = ( let b = 10 ) * 3 > 10 )
I've honestly no idea, at first/quick read, what the hell that would produce.
Is a
going to be just true
? 'cause if not, this proposal violates
operator precedence.
If yes ... why would anyone write that ?
If yes ... why would anyone write that ?
I think it would have to be "yes" (and that's probably just a contrived example that doesn't demonstrate the usefulness).
Slightly less contrived, I could see the value in this, though. E.g.,
router.get('/user', (req, res, next) => {
if (let user = req.session.user) {
// do stuff with user here
} else {
res.status(401).end();
}
});
I don't think it works as cleanly with var
, but const
and let
has
some nice precedence with for-statements.
I say let's hold off until JavaScript gets pattern matching support (assuming it does). It's rather limiting otherwise, and the use case IMHO doesn't really merit a new syntax for it.
I often find myself wanting to do this in the case of while
. I've been
writing
for (let a; a = someLongCondition();) { doSomethingWith(a); }
In that spirit, an oddball proposal:
while (let a = someLongCondition(); a) { ...use a... }
if (let a = someLongCondition(); a) { ...use a... }
On Fri, Sep 16, 2016 at 2:43 AM, Bob Myers <rtm at gol.com> wrote:
I often find myself wanting to do this in the case of
while
. I've been writingfor (let a; a = someLongCondition();) { doSomethingWith(a); }
In that spirit, an oddball proposal:
while (let a = someLongCondition(); a) { ...use a... } if (let a = someLongCondition(); a) { ...use a... }
switch( let a = something() ) { }
would ' do { ... use a ... } while( let a = f() ); ' work?
( (let a = f() ) > 3 ) ? (a-3) : (a+3) //ternary operator?
which begins to look like '( [let/var/const] ... ) ' in any expression.
I saw it mentioned in several messages earlier about the comma operator as applied to the let/var statement... I suppose that IS an issue.
for example : if( let a = 1, b = 0 )
-
if( 1, 0 ) the comma operator clears the expression stack and results with only the value after the comma... so you can chain some expressions that may have side effects... /* if( a=f(), b=g(a) ) */
-
if the comma is then interpreted as an operator for the declaration, then the result is... undeterminate... because there's really not a testable result ?
On Fri, Sep 16, 2016 at 10:43 AM, J Decker <d3ck0r at gmail.com> wrote:
I saw it mentioned in several messages earlier about the comma operator as applied to the let/var statement... I suppose that IS an issue.
for example : if( let a = 1, b = 0 )
- if( 1, 0 ) the comma operator clears the expression stack and results with only the value after the comma... so you can chain some expressions that may have side effects... /* if( a=f(), b=g(a) ) */
Sorry I did that again; ... that would really be like ' a = ( f(), b=g(a)) ' and would fail.... I always do that. maybe
if( ( a=f() ), g(a) ) intead?
Why not more generally - allow let/var declarations in expressions?
coming from a long and rich C background, I have no issues with the existing mechanisms... but for those languages that do support variable declarations in for loops; I've always wondered why not any expression?
if( let a = ( let b = 10 ) * 3 > 10 ) ... or ...
c = (let a = b*d)
granted, the scope is extremely limited in the last case...
Danielle McLean wrote:
variables declared using
let
orconst
would be scoped to the individualif
orwhile
statement, rather than the containing block. In other words, the above syntax would be equivalent to the following currently-valid form I ended up writing:{ const oldValue = _.get(object, 'some.long.path'); if (oldValue) object.some.long.path = transform(oldValue); }
What about else
blocks, would the variables be available in them as well?
How so? Assignment is already possible in control structures. I think this reads better:
if (let a = foo) {
Than:
let a;
//...
if (a = foo) {
Having the let
or const
inside the conditional part clarifies the
intent. There's an argument for not doing assignment inside the conditional
part, but it's subjective and people will write code that way regardless.
I'd much rather see let
or const
next to code like that if it means
mistakes are less likely to be made.
What about else if
?
An alternative to the block which you ended up with is to extract that logic to a function, which provides something which can be tested too. Possibly overkill for oneliners like this though.
However, writing a lot of code like this myself (get a value, if it's truthy do something, else do other), that's a nice idea for an extension that doesn't add extra variable bindings to the containing scope.
In current ECMAScript, it is legal to place a variable declaration inside the
initialiser of a for
loop, as well as to declare the variable used by a
for...in
or for...of
loop within the declaring expression:
for (let i = 0; i < 5; ++i) console.log(i); for (let item of collection) process(item);
When this syntax is used with let
or const
, the resulting variable is
scoped to the loop and is not visible to the rest of the surrounding block.
I propose that this syntax be extended, making it legal to place a variable
declaration within the condition of an if
or while
statement. Any truthy
value will cause the if
block to run or while
loop to repeat, as usual -
the advantage is that the particular truthy value is bound to a variable and
can be used inside the conditional block. For example, here is the situation
that prompted my writing this proposal:
if (const oldValue = _.get(object, 'some.long.path')) { object.some.long.path = transform(oldValue); }
As with the existing behaviour of declarations inside for
, variables declared
using let
or const
would be scoped to the individual if
or while
statement, rather than the containing block. In other words, the above syntax
would be equivalent to the following currently-valid form I ended up writing:
{ const oldValue = _.get(object, 'some.long.path'); if (oldValue) object.some.long.path = transform(oldValue); }
Another use case which C aficianados might recognise:
while (const c = getchar()) { process(c); }
This syntax is already legal in C++, although not in C - in general this support is known as "anaphoric if", as it allows the body of the statement to refer back to the condition value. It's especially helpful in languages with truthiness, which ECMAScript has, as it allows access to the specific truthy value without further finagling.
Thoughts?
I say let's hold off until JavaScript gets pattern matching support (assuming it does). It's rather limiting otherwise, and the use case IMHO doesn't really merit a new syntax for it.
The main barrier that I can see is that this requires new semantics. At the moment, variable declarations don't have any kind of usable result. If you consider
let a = eval('let b = 1');
console.log(a);
//-> undefined
This sounds like an easy thing to solve, but how about this:
if (let a = foo(), b = bar()) {
}
Does the block execute if a
and b
are both truthy, or just b
? My gut
instinct says "if bar() is truthy", but it still seems awkward. Any option
might be confusing depending on your level of experience. What about this:
if (let { a, b } = foo) {
}
Does the block execute if a
and b
are both truthy, just b
, or if
foo
is truthy? I'd lean towards foo
in this case, but I think it looks
pretty bad and I'd hate to see it in code. It might make more sense to
throw for destructuring or if there's more than one assignment.
If yes ... why would anyone write that ?
I think it would have to be "yes" (and that's probably just a contrived example that doesn't demonstrate the usefulness).
Slightly less contrived, I could see the value in this, though. E.g.,
router.get('/user', (req, res, next) => {
if (let user = req.session.user) {
// do stuff with user here
} else {
res.status(401).end();
}
});
I don't think it works as cleanly with var
, but const
and let
has
some nice precedence with for-statements.
For what it's worth, I'm on the side of people that do not want to see assignment statements in control structures. I don't think it is necessary and it results in code that is harder to read.
Does this really need new semantic interpretation of the syntax? Using the
Array.prototype
methods .forEach
and .map
already mitigates this
problem as far as I can tell by having a different bound variable (argument
in this case) for each call.
I agree that the behavior may be non-intuitive if you have a background coming from Java or C++ but the implications would be quite far-reaching and the backward compatibility with previous versions would be difficult to handle. Wouldn't this require a new 'use strict'-like mode? 2016年9月14日(水) 7:51 Dan Peddle <dan at flarework.com>:
"Bergi" <a.d.bergi at web.de> wrote:
What about
else
blocks, would the variables be available in them as well?
No. If the else
block executes, then the variable's value would be
falsy and therefore presumably not useful for further processing. Of
course, there are multiple falsy values in ES, but knowing which
specific falsy value a condition produced is far less useful than
knowing which specific truthy value a condition produced.
If you've got a use case for the variable's scope extending into the
else
block, though, feel free to change this. ;)
"Alan Johnson" <alan at breakrs.com> wrote:
What about
else if
?
As with a standalone else
, the else if
branches are only reached
if the value from the if
branch was falsy and therefore presumably
not useful. So, again, the variable from the original if
condition
need not be available.
It should however be possible to declare another variable in an
else if
's condition, for consistency. Like this:
if (const x = expr()) {
// use x
} else if (const x = expr2()) {
// use x in a different way
} else {
// couldn't get either kind of x :(
}
I agree but at the same time those examples simply look like bad coding practices to me and we can't completely hide from those. Since it's new semantics we shouldn't have to worry about it breaking something existing and it would be really easy to do a transpile back into ES5 or ES6 should people want to use it ahead of time.
Just my 2 cents. You certainly have valid points. The only awkward thing, in my opinion, is if we're using let and const we're going to have to allow var as well (it would be odd that, in a single place, you can use let and const but not var). Not sure how var should be really handled here; probably allow it but make it a bad practice to use var in this type of declaration. In my opinion anyway.
In current ECMAScript, it is legal to place a variable declaration inside the
initialiser of a for
loop, as well as to declare the variable used by a
for...in
or for...of
loop within the declaring expression:
for (let i = 0; i < 5; ++i) console.log(i); for (let item of collection) process(item);
When this syntax is used with let
or const
, the resulting variable is
scoped to the loop and is not visible to the rest of the surrounding block.
I propose that this syntax be extended, making it legal to place a variable
declaration within the condition of an if
or while
statement. Any truthy
value will cause the if
block to run or while
loop to repeat, as usual -
the advantage is that the particular truthy value is bound to a variable and
can be used inside the conditional block. For example, here is the situation
that prompted my writing this proposal:
if (const oldValue = _.get(object, 'some.long.path')) { object.some.long.path = transform(oldValue); }
As with the existing behaviour of declarations inside for
, variables declared
using let
or const
would be scoped to the individual if
or while
statement, rather than the containing block. In other words, the above syntax
would be equivalent to the following currently-valid form I ended up writing:
{ const oldValue = _.get(object, 'some.long.path'); if (oldValue) object.some.long.path = transform(oldValue); }
Another use case which C aficianados might recognise:
while (const c = getchar()) { process(c); }
This syntax is already legal in C++, although not in C - in general this support is known as "anaphoric if", as it allows the body of the statement to refer back to the condition value. It's especially helpful in languages with truthiness, which ECMAScript has, as it allows access to the specific truthy value without further finagling.
Thoughts?
I really like the idea of declaring a variable directly in the conditional itself. Many other languages do it. It's certainly not a critical thing (it makes 2 lines of code into 1) but I certainly would like it to happen. Considering it only moves the declaration I'm not convinced it makes code harder to read; in fact since you are explicitly saying it's part of the conditional you're declaring it in I feel like that makes it more clear as there is no longer a risk of someone re-using that variable outside of, say, the while loop it's declared in (which is what can happen today).
I know we don't have voting but this sure has my vote. I'd love to see it championed at an upcoming meeting.
On 14 September 2016 at 17:58:24, Viktor Kronvall (viktor.kronvall at gmail.com(mailto:viktor.kronvall at gmail.com)) wrote:
Does this really need new semantic interpretation of the syntax? Using the
Array.prototype
methods.forEach
and.map
already mitigates this problem as far as I can tell by having a different bound variable (argument in this case) for each call.I agree that the behavior may be non-intuitive if you have a background coming from Java or C++ but the implications would be quite far-reaching and the backward compatibility with previous versions would be difficult to handle. Wouldn't this require a new 'use strict'-like mode?
No, adding anaphoric if as I have described it will require neither
new semantic interpretation of the syntax nor a new strictness
directive. Currently, it is a syntax error to write a variable
declaration within an if
or while
condition, so there is no valid
code which contains the proposed syntax.
Also note that under this proposal, declarations made using the var
keyword would still be hoisted to function scope, not scoped to the
body associated with the condition - i.e., there would be no semantic
difference whatsoever between the following two snippets:
if (var stuff = some.cool(expression)) doThings(stuff); // equivalent to var stuff; if (stuff = some.cool(expression)) doThings(stuff);
Only declarations made with the newer let
and const
keywords,
which are never hoisted to function scope anyway, would be narrowly
scoped to the condition and its body.
if (let stuff = expr) doThings(stuff); // equivalent to { let stuff = expr; if (stuff) doThings(stuff); }
(An aside: as the last example demonstrates, the if
or while
statement body should not need braces to isolate the scope in this
way. This is consistent with the current behaviour for declarations in
loops.)
Given that let x == 10
or let x === 10
is illegal, it doesn’t seem too bad to allow if (let x = f(y))
, LexicalDeclaration is visually distinct from EqualityExpression because of the let
or const
prefix.
On Sep 14, 2016, at 6:41 PM, Jordan Harband <ljharb at gmail.com> wrote:
While I like the idea of making it simpler to restrict the scope of variables, currently a reigning best practice is to never do assignment in conditionals, since it can be an easy typo from
==
or===
, and because it conflates assignment with expression truthiness, harming readability.This seems like it runs afoul of the latter, certainly, and I haven't yet convinced myself whether it creates typo hazards (I'm thinking no, but wanted to bring it up just in case).
Given that let x == 10
or let x === 10
is illegal, it doesn’t seem too bad to allow if (let x = f(y))
, LexicalDeclaration is visually distinct from EqualityExpression because of the let
or const
prefix.
On 09/12/2016 05:32 PM, Danielle McLean wrote:
In current ECMAScript, it is legal to place a variable declaration inside the initialiser of a
for
loop, as well as to declare the variable used by afor...in
orfor...of
loop within the declaring expression:for (let i = 0; i < 5; ++i) console.log(i); for (let item of collection) process(item);
When this syntax is used with
let
orconst
, the resulting variable is scoped to the loop and is not visible to the rest of the surrounding block.I propose that this syntax be extended, making it legal to place a variable declaration within the condition of an
if
orwhile
statement. Any truthy value will cause theif
block to run orwhile
loop to repeat, as usual - the advantage is that the particular truthy value is bound to a variable and can be used inside the conditional block.
My initial reaction was positive, but now I don't think it works.
First, other places in the grammar do not restrict let/const to a single variable. Should
if (let a=0, b=1, c=0) { ... }
execute the if block or not? The obvious solution is to require a single variable, which means the grammar for these let/consts is different from others. What about
x = { a: 1 }; if (let {a} = x) { ... }
Second, that previous example makes it unclear to me at first glance what the intended semantics should be. I could imagine this printing either 1 or 2:
h = { foo: 0}; if (let {bar=1} = h) { print(1); } else { print(2); }
Is the conditional based on the variable's final value, or on whether or not the destructuring found a match? I could argue for either one, so even if there's a natural way to resolve my first problem, I think the code looks ambiguous to the eye.
if (let { children } = node) { print("interior node"); } else { print("leaf node"); }
Again, the simplest way to resolve this is to restrict it to "let/const IDENTIFIER = expression", but it feels weird to have different rules for this particular case. for(let...) on the other hand, does not attempt to use the let expression as a value, so it does not encounter any of these problems.
As a minor issue, it also feels a little awkward to special-case this conditional expression. I can do
if (let x = foo()) print(x)
but not
(let x = foo()) && print(x)
For what it's worth, that specific use case would be addressed by tc39/String.prototype.matchAll ;-)
if( let a = ( let b = 10 ) * 3 > 10 )
I've honestly no idea, at first/quick read, what the hell that would produce.
Is a
going to be just true
? 'cause if not, this proposal violates
operator precedence.
If yes ... why would anyone write that ?
I like this proposal. Specially for while
loops.
When I want to iterate all matches of a global regex, I always think the variable declaration at the top seems ugly
let match;
while (match = regex.exec(string)) {
// ...
}
This looks better:
while (let match = regex.exec(string)) {
// ...
}
While I like the idea of making it simpler to restrict the scope of
variables, currently a reigning best practice is to never do assignment in
conditionals, since it can be an easy typo from ==
or ===
, and because
it conflates assignment with expression truthiness, harming readability.
This seems like it runs afoul of the latter, certainly, and I haven't yet convinced myself whether it creates typo hazards (I'm thinking no, but wanted to bring it up just in case).
I saw it mentioned in several messages earlier about the comma operator as applied to the let/var statement... I suppose that IS an issue.
for example : if( let a = 1, b = 0 )
-
if( 1, 0 ) the comma operator clears the expression stack and results with only the value after the comma... so you can chain some expressions that may have side effects... /* if( a=f(), b=g(a) ) */
-
if the comma is then interpreted as an operator for the declaration, then the result is... undeterminate... because there's really not a testable result ?
I often find myself wanting to do this in the case of while
. I've been
writing
for (let a; a = someLongCondition();) { doSomethingWith(a); }
In that spirit, an oddball proposal:
while (let a = someLongCondition(); a) { ...use a... }
if (let a = someLongCondition(); a) { ...use a... }
On Fri, Sep 16, 2016 at 10:43 AM, J Decker <d3ck0r at gmail.com> wrote:
I saw it mentioned in several messages earlier about the comma operator as applied to the let/var statement... I suppose that IS an issue.
for example : if( let a = 1, b = 0 )
- if( 1, 0 ) the comma operator clears the expression stack and results with only the value after the comma... so you can chain some expressions that may have side effects... /* if( a=f(), b=g(a) ) */
Sorry I did that again; ... that would really be like ' a = ( f(), b=g(a)) ' and would fail.... I always do that. maybe
if( ( a=f() ), g(a) ) intead?
On Fri, Sep 16, 2016 at 2:43 AM, Bob Myers <rtm at gol.com> wrote:
I often find myself wanting to do this in the case of
while
. I've been writingfor (let a; a = someLongCondition();) { doSomethingWith(a); }
In that spirit, an oddball proposal:
while (let a = someLongCondition(); a) { ...use a... } if (let a = someLongCondition(); a) { ...use a... }
switch( let a = something() ) { }
would ' do { ... use a ... } while( let a = f() ); ' work?
( (let a = f() ) > 3 ) ? (a-3) : (a+3) //ternary operator?
which begins to look like '( [let/var/const] ... ) ' in any expression.
In current ECMAScript, it is legal to place a variable declaration inside the initialiser of a
for
loop, as well as to declare the variable used by afor...in
orfor...of
loop within the declaring expression:for (let i = 0; i < 5; ++i) console.log(i); for (let item of collection) process(item);
When this syntax is used with
let
orconst
, the resulting variable is scoped to the loop and is not visible to the rest of the surrounding block.I propose that this syntax be extended, making it legal to place a variable declaration within the condition of an
if
orwhile
statement. Any truthy value will cause theif
block to run orwhile
loop to repeat, as usual - the advantage is that the particular truthy value is bound to a variable and can be used inside the conditional block. For example, here is the situation that prompted my writing this proposal:if (const oldValue = _.get(object, 'some.long.path')) { object.some.long.path = transform(oldValue); }
As with the existing behaviour of declarations inside
for
, variables declared usinglet
orconst
would be scoped to the individualif
orwhile
statement, rather than the containing block. In other words, the above syntax would be equivalent to the following currently-valid form I ended up writing:{ const oldValue = _.get(object, 'some.long.path'); if (oldValue) object.some.long.path = transform(oldValue); }
Another use case which C aficionados might recognise:
while (const c = getchar()) { process(c); }
This syntax is already legal in C++, although not in C - in general this support is known as "anaphoric if", as it allows the body of the statement to refer back to the condition value. It's especially helpful in languages with truthiness, which ECMAScript has, as it allows access to the specific truthy value without further finagling.
Thoughts?