-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
a place to put variables in only while loop scope #5070
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
Idea: currently, we support this: while (foo) : (bar) {
baz
} Should we also support this? while (init) : (foo) : (bar) {
baz
} ? Or, alternately, (init) : while (foo) : (bar) {
baz
} e.g. (var a: usize = 0) : while (a < 8) : (a += 1) {
} A refined variation of the latter might be good, as it has the following properties:
|
interesting ideas, but (var a: usize = 0) : while (a < 8) : (a += 1) {} your proposal has:
so its just like a c for loop |
Anyone coming from another C like language is instantly going to know how to write and read loop declarations like C: for (initialization ; condition; increment) {
body
} Maybe I'm missing something. Is there a reason to avoid using C style loops? I assume the purpose of this is to figure out how to declare new variables in the scope of the for (var i = 0; i < 100; i++) {
console.log(i);
} |
It becomes worse when we add more variables... 😉 I think starting a new block is a good solution in this condition. Otherwise just give variable names i, i2, i3, i4, etc.
Problem solved if the variables defined in
here is the rest of my proposal:
edit3: only use the absolute value of |
↑ updated: changed range(min, max) to range(begin, end, non_zero_step) edit: well, if you really want zeros that's no problem too |
No, you should take
|
Right now Zig's for loops already act like a foreach. It is possible to implement ranges in compile-time Zig doing something like this: fn range(comptime T: type, comptime start: usize, comptime end: usize) []T {
const Len = end - start;
comptime {
var result: [Len]T = [_]T{0} ** Len;
var i: usize = 0;
while (i < Len) : (i += 1) {
result[i] = start + i;
}
return result[0..];
}
}
test "range" {
for (range(i64, 0, 10)) |i| {
std.debug.warn("{} ", .{i});
}
}
Output:
0 1 2 3 4 5 6 7 8 9 Caveat this will not work for runtime only array lengths however for (runtimeArray) |value, index| {
} |
You can also do it at runtime and without reserving static memory like this: const std = @import("std");
fn rangeHack(len: usize) []void {
// No chance of UB [*]void is a zero-size type
return @as([*]void, undefined)[0..len];
}
pub fn main() void {
for (rangeHack(10)) |_, i| {
std.debug.warn("{} ", .{i});
}
}
Output:
0 1 2 3 4 5 6 7 8 9 But this is definitely a hack. |
+1 for this question. What is the aversion to C-style for loops? I am okay with a for-range syntax, but I find the C-style for loop much easier to type and easier to read than the current while loop idiom and unfortunately I find myself using that idiom more than for loops as they are. |
my only issue with C-style for loops is they have two different places to write the loop body for (int i = 0; i < 10; i++) {}
// versus
for (int i = 0; i < 10;) {i++;} isnt this redundant? zig has the same issue var i : usize = 0;
while (i < 10) {i += 1;}
// versus
var i : usize = 0;
while (i < 10) : (i += 1) {} |
Alternatively we could have something like |
They are not redundant. These three loops have slightly different semantics in Zig: var curr: ?*Node = getListHead();
// loop 1
while (curr) |node| : (curr = node.next()) {
if (cond_a) { continue; }
if (cond_b) { break; }
}
// loop 2
while (curr) |node| {
defer curr = node.next();
if (cond_a) { continue; }
if (cond_b) { break; }
}
// loop 3
while (curr) |node| {
if (cond_a) { continue; }
if (cond_b) { break; }
curr = node.next();
} Loop 1: |
Use anonymous blocks to limit the scope of variables. |
nymous blocks also work well - the label is a comment and the first curly is pushed over where it belongs.
|
I realize this issue is closed but after reading some of the comments I see an idea that could address this and other issues. Namely, to provide a way to define symbols for the next statement/expression. Something like this:
So for loops you'd have: with (var i : usize = 0) while (i < 10) : (i += 10) {
...
} And this could also be used to define symbols/aliases for functions: with (comptime const T = @TypeOf(a).Pointer.child)
pub fn foo(a: var) !T {
var b: T = undefined;
// ...
return T.init(...);
} Maybe you could use struct literals for the |
I'm not so much a fan of anonymous blocks when you have a lot of nested loops Desired: while(std.utils.Range(0,10)) |i| { // statement cannot both be a declaration and a '.next()' call
// do stuff
} Creating an iterator is not the same as a testing a boolean expression though. Maybe the for(std.utils.SliceIterator(arr[4..10]) |value| {
// do stuff
}
const iterate = std.utils.SliceIterator;
for( iterate(arr[4..10])) |value| {
// do stuff
}
for(std.utils.Range(0,10) ) |i| {
// do stuff
} Uglier, but more versatile? |
There is one thing that is open to changing here which is having {var i: i32 = 0; while (i < 10) : (i += 1) {
blah();
}} |
At that point, it really looks like a C |
inconsistent coding style on the spot, nitpicking starts... While if/while/for/switch all support
well, just small complaint. I think
|
Uh oh!
There was an error while loading. Please reload this page.
edit: this is the pattern that @andrewrk chose to settle with
this is from @Hejsil 's interface demo. also see a reddit thread that mentions this pattern
doing this is to avoid:
compare with a C for loop:
the c for loop has
versus an example from the zig docs:
zig while loop has:
related zen:
avoid local maximums
communicate intent precisely
favor reading code over writing code
only one obvious way to do things
reduce the amount one must remember
minimize energy spent on coding style
status quo inhibits all of these. can we make this better?
The text was updated successfully, but these errors were encountered: