ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.9k stars 2.55k forks source link

Nested While Loop runs loops sequentially rather than running nested loop per outer loop #13043

Closed jowi-dev closed 2 years ago

jowi-dev commented 2 years ago

Zig Version

0.9.1

Steps to Reproduce

Was Following RayTracing in one Weekend using Zig, when I encountered a bug that I couldn't figure out. With the code structured as


    while (j > 0) : (j = -1) {
        while (i < IMAGE_WIDTH) : (i += 1) {
            const r: f16 = @intToFloat(f16, i) / @intToFloat(f16, (IMAGE_WIDTH - 1));
            const g: f16 = @intToFloat(f16, j) / @intToFloat(f16, (IMAGE_HEIGHT - 1));
            const b: f16 = 0.25;

            const ir: u16 = @floatToInt(u16, (255.999 * r));
            const ig: u16 = @floatToInt(u16, (255.999 * g));
            const ib: u16 = @floatToInt(u16, (255.999 * b));

            try print("{} {} {}\n", .{ ir, ig, ib });
            std.debug.print("i value: {}\n", .{i});
        }

        std.debug.print("j value: {}\n", .{j});
    }

The debug output will be (shortened): i 0..255 j 255..0

Note that when the inner while loop is nested in a function call it works fine. Included working code sample as well:


pub fn main() anyerror!void {
    const stdout = std.io.getStdOut().writer();
    const print = stdout.print;

    const IMAGE_HEIGHT: u16 = 256;
    const IMAGE_WIDTH: u16 = 256;

    try print("P3\n{} {}\n255\n", .{ IMAGE_WIDTH, IMAGE_HEIGHT });

    var j: u16 = IMAGE_HEIGHT - 1;

    while (j > 0) {
        try parseRGB(j, IMAGE_WIDTH, IMAGE_HEIGHT);
        std.debug.print("j value: {}\n", .{j});
        j = j - 1;
    }
}

// Be sure to add a type after the parenthesis and before the {
fn parseRGB(j: u16, IMAGE_WIDTH: u16, IMAGE_HEIGHT: u16) !void {
    const stdout = std.io.getStdOut().writer();
    const print = stdout.print;
    var i: u16 = 0;

    while (i < IMAGE_WIDTH) : (i += 1) {
        const r: f16 = @intToFloat(f16, i) / @intToFloat(f16, (IMAGE_WIDTH - 1));
        const g: f16 = @intToFloat(f16, j) / @intToFloat(f16, (IMAGE_HEIGHT - 1));
        const b: f16 = 0.25;

        const ir: u16 = @floatToInt(u16, (255.999 * r));
        const ig: u16 = @floatToInt(u16, (255.999 * g));
        const ib: u16 = @floatToInt(u16, (255.999 * b));

        std.debug.print("i value: {}\n", .{i});
        try print("{} {} {}\n", .{ ir, ig, ib });
    }
}

Expected Behavior

The debug output would be i value 0..255 j value 255 i value 0..255 j value 254 i value 0..255 j value 253 .... etc

Actual Behavior

The debug output will be (shortened): i 0..255 j 255..0

And then the program will exit

jowi-dev commented 2 years ago

IM A BIG DUMMY CLOSING

Edit for those who do the same - it matters where you initialize that inner variable :joy: