Testing == null does not work with type variables?

I have a function specificPrintIsNull which performs as expected, testing if an parameter with optional type is null or not, but the genericPrintIsNull always says the value is not null. I don’t understand why there is a difference.

const std = @import("std");

fn genericPrintIsNull(comptime T: type, v: ?T) void {
    if (v == null) {
        std.debug.print("It is null\n", .{});
    } else {
        std.debug.print("It is NOT null\n", .{});
    }
}

fn specificPrintIsNull(v: ?u8) void {
    if (v == null) {
        std.debug.print("It is null\n", .{});
    } else {
        std.debug.print("It is NOT null\n", .{});
    }
}

pub fn main() void {
    var i: ?u8 = null;
    genericPrintIsNull(@TypeOf(i), i);
    specificPrintIsNull(i);
    i = 42;
    std.debug.print("After assignment\n", .{});
    genericPrintIsNull(@TypeOf(i), i);
    specificPrintIsNull(i);
}

Here @TypeOf(i) = ?u8. In genericPrintIsNull we now have T=?u8 and thus it expects a second parameter of type ?(?u8). By providing a parameter of type ?u8, it considers the parameter to be non-null.

In short: double optionals make syntax quite confusing.

1 Like

Yes, it makes sense. Here is the fixed version, thanks:

const std = @import("std");

fn genericPrintIsNull(comptime T: type, v: ?T) void {
    if (v == null) {
        std.debug.print("It is null\n", .{});
    } else {
        std.debug.print("It is NOT null\n", .{});
    }
}

fn specificPrintIsNull(v: ?u8) void {
    if (v == null) {
        std.debug.print("It is null\n", .{});
    } else {
        std.debug.print("It is NOT null\n", .{});
    }
}

pub fn main() void {
    var i: ?u8 = null;
    genericPrintIsNull(u8, i);
    specificPrintIsNull(i);
    i = 42;
    std.debug.print("After assignment\n", .{});
    genericPrintIsNull(u8, i);
    specificPrintIsNull(i);
}

Side question: is there a predefined function to “unwrap” the type of an optional variable and get the base type? (For instance, @BaseOf(?u8) → u8.) I don’t find it Documentation - The Zig Programming Language

@typeInfo(?u8).Optional.child is your friend.

2 Likes

Also std.meta.Child to be less verbose (and works on anything with a child type).

3 Likes