Kafkaesque Zig code

I was having trouble falling asleep so I dreamt up this nightmarish code sample:

const std = @import("std");

pub fn main() void {
    var i: usize = 0;
    while (do: {
        break :do @typeInfo(@TypeOf(while (true) {
            break;
        })) == .Void and @typeInfo(@TypeOf(while (true) {})) == .NoReturn and @typeInfo(@TypeOf(while (false) {})) != .NoReturn;
    }) : (i += 1) {
        std.debug.print("Hello {d}\n", .{i});
        if (i == 10) {
            break;
        }
    }
}

Can you figure out what’s going on here?

7 Likes

Becomes pretty clear when you rewrite it like this:

const std = @import("std");

// zig fmt: off
pub fn main() void {
    var i: usize = 0;
    while (@typeInfo(@TypeOf(while (true) { break; })) == .Void and
        @typeInfo(@TypeOf(while (true) {})) == .NoReturn and
        @typeInfo(@TypeOf(while (false) {})) != .NoReturn
    ) : (i += 1) {
        std.debug.print("Hello {d}\n", .{i});
        if (i == 10) {
            break;
        }
    }
}

Since the outer while loop’s funky condition evaluates to true, this program produces the same output as this one:

const std = @import("std");

pub fn main() void {
    for (0..11) |i| {
        std.debug.print("Hello {d}\n", .{i});
    }
}
4 Likes

I hope you sleep better tonight.

I broke it down below. The while is three things “and” together.
Since they are all equal. it will loop forever until i=10 and then break out

The first three debug.prints show the three evaluations.

const std = @import("std");

pub fn main() void {

    var i: usize = 0;

    std.debug.print("{any}\n", .{@TypeOf(while (true) { break; })});
    std.debug.print("{any}\n", .{@TypeOf(while (true) {})});
    std.debug.print("{any}\n", .{@TypeOf(while (false) {})});


    while (do:
        { break
            :do
                @typeInfo(@TypeOf(while (true) { break; })) == .Void
            and @typeInfo(@TypeOf(while (true) {}  ))       == .NoReturn
            and @typeInfo(@TypeOf(while (false) {} ))       != .NoReturn;
        }
        ) : (i += 1)
        { std.debug.print("Hello {d}\n", .{i}); if (i == 10) { break; } }
}

It’s not obvious that @TypeOf(while(true) {}) is noreturn. I think I gave the game away with an explicit check. @TypeOf(while(true) {}) != .Void would be more mysterious.

Version 2.0 of confounding while loop:

const std = @import("std");

pub fn main() void {
    var i: usize = 0;
    while (do: {
        break :do @typeInfo(@TypeOf(while (true) {
            switch (i % 2) {
                0 => @panic("Not an odd number"),
                1 => @panic("Not an even number"),
                else => break,
            }
        })) == .Void and @typeInfo(@TypeOf(while (true) {})) != .Void and @typeInfo(@TypeOf(while (false) {})) == .Void;
    }) : (i += 1) {
        std.debug.print("Hello {d}\n", .{i});
        if (i == 10) {
            break;
        }
    }
}