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;
}
}
}