proposal-do-expressions
proposal-do-expressions copied to clipboard
Rules for nested do-expressions
In nested do-expressions, does an ExpressionStatement affect all enclosing do-expressions (in the same function) or only the innermost?
It usually doesn't matter, but consider:
function f() {
return do {
1;
while (true) {
(do { 2; }, do { break; });
}
};
}
If the rule is "all enclosing do-expressions", then f() returns 2.
If the rule is "only the innermost", then f() returns 1.
...Never mind, I think this returns undefined regardless. So maybe it doesn't matter.
Now I am back to thinking it returns either 1 or 2, so there's an actual design choice to make here.
My intuition:
function f() {
return do {
1;
while (true) {
(
do { 2; }, // => 2
do { break; }
// not sure if the "break" breaks out of the `while`, or the `do` -
// if the `do` (my expectation), it's an infinite loop,
// so i'll assume the `while`, thus => `undefined`
); // (2, undefined) => `undefined`
} // => `undefined`
}; // => `undefined`
} // => `undefined`
In other words, either an infinite loop, or undefined. (I'm aware that while (true) { 3; break; } currently completes to 3, but the semantics of do { break; } aren't yet clear)
Oh, cool, I assumed the opposite about break. In any case, just assume I'm breaking out of the loop (using a labeled break, if necessary).
I'll file a separate issue to clarify the interaction between do-expressions and break.
You're right, it's undefined, because a while loop always produces a value. Let me change the example:
function f() {
return do {
a: while (true) {
1;
(do { 2; }, do { break a; });
}
};
}
This moves the 1; inside the loop. (The label on the loop is to avoid the whole question of issue #24.)
Now I claim the answer is either 1 or 2.
How you have it written, you could have an infinite loop if break only breaks out of the do block, then it never breaks out of the while loop
I suppose to some extent the question of do or while isn't super important for the case of the completion value, assuming labels can still be used, e.g.
function f() {
return do {
1;
loop: while (true) {
(do { 2; }, do { break loop; });
}
};
}
With that, we're back to the original question of completion values.
I think my expectation here would be that expressions in general (including do expressions) should not be allowed to have empty completion values ever since none of the expression semantics expect that currently and it seems like it would lead to extreme confusion most of the time. Given that, I'll second do { break loop; } having a value of undefined.
Edit: Woops, new post while I wrote that. Given the above, your loop would still return undefined because (do { 2; }, do { break a; }); would evaluate to type: break, value: undefined. The value would have to be empty for the 1 to be picked up.
Right: unless we change the spec, the answer is "only the innermost"; i.e. the new example returns 1, not 2.
But does that really make sense? It seems hard to explain why things would work that way.
Maybe the spec is like this because until now, expressions have not been able to break or continue. Now that they can, it makes sense to specify them to use UpdateEmpty, just like statements.
If we don't, then (do { 2; }, do { break; }) has slightly different behavior from (do { 2; break; }) which seems like a WAT.
@pitaj Labeled break doesn't jump back to the label and restart the loop. It breaks out of the loop with the given label. The program continues at the next statement after the loop.
It does appear you're correct. I've edited my comment.
I think this has to be 1 (or possibly undefined), not 2. We could special-case comma-expressions in statement position, but honestly I don't expect them to ever come up in practice.