-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Proposal: Rename for
to each
#7826
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
In my opinion, With regards to the |
Oh yeah, I was going to write that up too, wasn't I? One sec. |
Why not foreach? Sounds more like a loop to me than "each" |
Isn't the ranged iteration issue sort of orthogonal to the choice of keyword? The main problem is that most modern languages embrace the view that for loops should support all iterable objects (arrays, hash maps, ranges, custom types, etc.), while Zig only allows structural iteration over arrays and slices. While this remains so, there will always be complaints from people coming from Rust, Julia, younameit that Zig makes ranged iteration unnecessarily difficult. Calling the for loop |
@Guigui220D It's not necessarily a loop though -- it might be vectorised or tiled by the optimiser. @zzyxyzz The name is not the only factor, but I believe it is significant -- it may seem like false advertising. We will not simply support other kinds of iteration, either, for established and well-documented reasons. |
As I see it, people have very specific assumptions of what a As a name, I think |
Accidentally reusing variables in loop conditions at the same nesting level is/was a common source of subtle bugs in C89, which is why C99 allowed declarations in expr-1 of the for-loop, restricting the scope appropriately. No shadowing occurs here, which makes it brittle when refactoring.
Looking at existing code, including std, this doesn't seem to be what people actually do 🤔 (because it's awkward/easy to forget?) In pursuit of a better language than C, I think this needs to be fixed. I suggested an optional initialization clause for the while statement, but not sure what syntax would work with the grammar goals. |
@ifreund, @EleanorNB,
I think it's inaccurate to assume that people use ranged iteration only out of sheer habit, and that the frustration with Zig's BTW, I'm not necessarily arguing against |
@cryptocode this has been rejected before in #5070. As mentioned there, a possible (partially social) fix would be to make zig fmt accept something like the following: {var i: usize = 0; while (i < 10) : (i += 1) {
// body
}} though I'd personally prefer to have the option of this variant as well: {var i: usize = 0;
while (i < 10) : (i += 1) {
// body
}} |
@ifreund but that relies on people scoping manually in the first place, which doesn't seem to be the case (easy to forget/awkward, especially when nesting). The reason for the rejection was basically "just remember to put braces there". This will be a significant source of bugs once people start refactoring large code bases. |
If there was a way to make |
@ifreund Ruby also uses a
|
It's all good to say people should do the right thing, but to borrow a phrase I've seen mentioned a few times, this an easy-to-trigger footgun. Most of Zig seems designed to eliminate categories of common bugs, yet this is reintroducing one from C89. I suppose an alternate solution could be for the compiler to emit a warning when a loop variable is reused. |
IMHO, var numbers = [_]usize{ 1, 2, 3, 4, 5 };
foreach (numbers) |*number| {
number.* += 1;
} is more readable than var numbers = [_]usize{ 1, 2, 3, 4, 5 };
each (numbers) |*number| {
number.* += 1;
} |
Closing in favor of status quo. |
Despite its rejection, #358 continues to be requested. I think the problem is that the name
for
evokes C-style ranged iteration, so people are surprised when it is exclusively for structural iteration. We could remedy that by choosing a more accurate name.each
is only one possibility: it could beforeach
,iterate
,lane
if we're feeling frisky -- but I'll leave the bikeshedding to the comments 😉. The remainder of this issue shall be musings on related subjects, and may be skipped if only a technical evaluation of the proposal is desired.A case against ranged iteration, so as to finally shut up the people still preaching for Proposal: for on ranges #358. As Andrew has pointed out many times, you can already do it with
while
. The laziest way involves leaking a local to the enclosing scope, but the lack of shadowing means that any potential unforeseen behaviour will probably be a compile error instead. So, in the worst case, the author of a ranged iteration has to do the awkward nested block thing. However, I personally believe this to be a benefit -- it makes the author reconsider if they really want a ranged iteration, or if what they actually want is a structural iteration, which 9 out of 10 times, it is. Continuing the theme of operant-conditioning our users.This proposal was born of a discussion on Discord with @ifreund, in which the idea was also raised of making the
while
clause optional and renamingwhile
toloop
so it wouldn't look weird without a clause. Upon further consideration, though, I think this is a mistake. Currently,while (true)
looks just a bit strange, so the developer is led to think of a sensible condition for the loop, rather than leaving it off and conditionallybreak
ing, which is much harder to unroll. On a more meta level, unconditionalloop
may be seen as "simpler" than conditional "loop" and thus be taught first, amplifying the previous problem as well as potentially leading to confusion later, when the learner wonders why a false condition runs anelse
branch but abreak
doesn't, when they've been led to believe that the two were semantically identical.Structural iteration has numerous well-known advantages, hence my stance that it should be encouraged where possible. However, there is one case where it shares many deficiencies with its ranged counterpart: SoA data. This involves the extraction and use of elements of multiple arrays at once, which there is currently no way to express directly; the best we can do is capture the index of one array and use it to access the others, which, unless we're very careful, loses many of the guarantees and optimisation opportunities that make structural iteration worthwhile in the first place. Proposal: Multi-object
for
loops #7257 exists to remedy this.The text was updated successfully, but these errors were encountered: