-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Proposal: Use a keyword instead of a colon in while loop continue expressions #8030
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@g-w1 Yes, thank you. May i ask you to explain why did you downvote? |
|
@g-w1 you already can use blocks in it. I took these examples from the langref. |
Oh sorry about that, I guess I didn't read carefully enough, but my second point still stands. |
I only really dislike the length of the keyword If we were willing to add another keyword, I'd propose Perhaps it would be enough to use a more visually distinct symbol? A new |
Hi Folks, my 20 cents I think that
|
@batiati This has come up before many times in an attempt to address various issues. In fact, that exact syntax was originally used in Zig. I address it somewhat in #472 There are some proposals currently open like #8019 and some that are closed like #5070, #358, #357. I also just realised the |
That use case is a kind of thing that makes me a big fan of zig, so, lets forget about the classic
|
Why don't we remove this syntax altogether in favor of |
@windows-h8r its not a good idea, there would more noise in the loop body and i like seeing at a glance what the loop will do when it repeats. |
@windows-h8r defer statements aren't able to get us the required semantics. See #472 (comment) |
On the contrary, the current syntax encourages writing long |
So the main problem seems to be to come up with a good short word. Maybe "step" fits the bill? while (i < 10) step (i += 1){ while (item)|it| step (item = it.next){ This needs a new keyword "step", but "continue" is not overloaded with a new meaning. |
What about an infix defer operator with the same semantics? var i: usize = 0;
while (i < 10 defer i += 1) {
std.debug.print("{}\n", .{i});
} |
I'll play devil's advocate here, why have this feature at all? const expect = @import("std").testing.expect;
test "while loop, with all the bells and whistles" {
var i: usize = 1;
var j: usize = 1;
while (i * j < 2000) : ({ i *= 2; j *= 3; }) {
const my_ij = i * j;
expect(my_ij < 2000);
}
}
test "while loop, but boring" {
var i: usize = 1;
var j: usize = 1;
while (i * j < 2000) {
const my_ij = i * j;
expect(my_ij < 2000);
i *= 2;
j *= 3;
}
} Maybe it's just me, but you can replace |
You can use the const expect = @import("std").testing.expect;
test "while loop, with step" {
var i: usize = 1;
var j: usize = 1;
while (i * j < 2000) : ({ i *= 2; j *= 3; }) {
const my_ij = i * j;
//I want just odd numbers
if (@rem(my_ij, 2) == 0) continue;
expect(my_ij < 2000);
}
}
test "while loop, without step" {
var i: usize = 1;
var j: usize = 1;
while (i * j < 2000) {
const my_ij = i * j;
//I want just odd numbers
if (@rem(my_ij, 2) == 0) continue;
expect(my_ij < 2000);
//this "step" block will not run on continue!
i *= 2;
j *= 3;
}
} |
Here is an alternative suggestion using const expect = @import("std").testing.expect;
test "while loop continue expression" {
var i: usize = 0;
while (i < 10) {} then {i += 1};
expect(i == 10);
}
test "while loop continue expression, more complicated" {
var i: usize = 1;
var j: usize = 1;
while (i * j < 2000) {
const my_ij = i * j;
expect(my_ij < 2000);
} then {
i *= 2;
j *= 3;
}
}
|
Allow me to come up with a counter-proposal, which is similar to @mlawren's while (condition) {
// do stuff
} continue {
// do stuff at the end of iteration or when `continue` is called.
} This would extend beyond for (collection) |item| {
// do stuff
} continue {
// special continuation logic
} This wouldn't interfere with the var foo =
while (stuff) { ... }
continue { ... }
else { ... }; The reason I prefer the
Alternatively, it could be called |
@ElectricCoffee while (condition) {
statement1;
} continue {
statement2;
} and while (condition) {
statement1;
// continue
statement2;
} |
@windows-h8r Incorrect. while (cond) {
// cond2=true
if (cond2) continue;
statement1; // skip
} continue {
statement2; // execute
}
while (cond) {
// cond2=true
if (cond2) continue;
statement1; // skip
statement2; // skip
} |
You're right, in the case when there's no while (condition) : (i += 1) {
stuff();
}
// is the same as
while (condition) {
stuff();
// :
i += 1;
} The point here is to have a syntax that is executed at every iteration regardless of circumstance. Using a continue block just lets you have more expressions without it looking cluttered. The syntax is ripped wholesale from Perl [src], except in Perl the block is called |
I stand corrected. However, that's such a subtle difference, despite the fact that they both use the Moreover, in my humble opinion, a language that uses a keyword as a statement in some contexts and a clause in other contexts is not a well-designed language. |
This is why I proposed this alternative syntax as well: while (cond) {
// cond2=true
if (cond2) continue;
statement1; // skip
} next {
statement2; // execute
} |
@ElectricCoffee That solves the second problem, but exacerbates the first one: The semantics aren't obvious. I have another idea. Remove the : syntax, as well as the errdefer statement, and combine their functionalities by parameterizing defer. defer(.All) array.deinit();
defer(.Loop) i += 1;
defer(.ReturnErr) a.b.deinit(); |
@windows-h8r the semantics would be the same as The main issue I see with your I see this as bad, because it makes it hard to spot at a glance, especially if your loop is complex or messy. Remember: programming languages only exists for humans to read; if they didn't we'd all be writing in binary. And yes, obvious semantics definitely help with that, so now it's a toss-up between obvious semantics and obvious obvious placement. How does EDIT: include the version of the comment I actually replied to |
@ElectricCoffee Good point. The while (i < 10) step (i += 1) {
sum += nums[i];
} |
@windows-h8r How is that any better than the block though? Except for limiting what code you can put in it |
|
The code is executed at the end though
The semantics are identical
That's fair |
I know. That's the point.
On the contrary, the keyword
No. The var foo = while (stuff) {
...
} next {
...
} else {
...
}; The semantics of an |
The semantics for an Your argument about putting a The block I'm proposing lets you do far more complex things than just setting a step size (and yes, that is what the ALGOL code does, it sets a step size of 0.5). Yes, it looks ridiculous for just a single expression, but the point is for it to allow for much more than that for example: while (current_word != EOF) {
// do stuff to process the word as part of some parsing
} next {
// this happens no matter what at the end of every iteration
current_word = advance_string(&str);
current_word = trim(to_lower(¤t_word));
} There's no way to do that nicely with the proposed |
In status quo zig continue expressions are not enough visually separated from the while condition, you have to parse it mentally a bit longer to know is it a long condition expression or its two expressions.
Also i think it would be easier to new users to understand what that expression does mean.
How it would look like:
The text was updated successfully, but these errors were encountered: