Zig: Comptime results in weird behaviour

Created on 18 May 2020  路  1Comment  路  Source: ziglang/zig

const std = @import("std");                                       

pub const Number = extern enum(u8) {                              
    Zero = 0,                                                     
    One = 1,                                                      
    Two = 2,                                                      
    Three = 3,                                                    
    Four = 4,                                                     
    Five = 5,                                                     
    Six = 6,                                                      
    Seven = 7,                                                    
    Eight = 8                                                     
};                                                                

export fn getNum(n: u8) Number {                                  
    comptime var x = Number.Zero;                                 

    if (n == 0) {                                                 
        x = Number.One;                                           
    }                                                             

    if (n == 1) {                                                 
        x = Number.Two;                                           
    }                                                             

    if (n == 2) {                                                 
        x = Number.Three;                                         
    }                                                             

    if (n == 3) {                                                 
        x = Number.Four;                                          
    }                                                             

    if (n == 4) {                                                 
        x = Number.Five;                                          
    }                                                             

    return x;                                                     
}                                                                 

pub fn main() !void {                                             
    std.debug.warn("getNum(0) == {}.\n", .{getNum(0)});           
}                                                                 

I was trying to see if I could get zig to optimize getNum(n) => Number(n + 1). When var x is declared as comptime then getNum always returns Number.Five. Otherwise it shows the expected behaviour.

bug stage1

Most helpful comment

If the intention is to get the whole function to always run at compile time, then wrapping the body of the function in comptime { will give you a proper error:

.\5372.zig:19:15: error: unable to evaluate constant expression
        if (n == 0) {
              ^
.\5372.zig:15:32: note: referenced here
export fn getNum(n: u8) Number {
                               ^

As you have it written, it seems like a compile error is missing, though, since the docs say this:

In Zig, the programmer can label variables as comptime. This guarantees to the compiler that every load and store of the variable is performed at compile-time. Any violation of this results in a compile error.

Maybe something like:

value of comptime var depends on runtime value

Another possible fix for what you intended is to use comptime at the call site and remove it from inside the function:

const std = @import("std");

pub const Number = extern enum(u8) {
    Zero = 0,
    One = 1,
    Two = 2,
    Three = 3,
    Four = 4,
    Five = 5,
    Six = 6,
    Seven = 7,
    Eight = 8,
};

fn getNum(n: u8) Number {
    var x = Number.Zero;

    if (n == 0) {
        x = Number.One;
    }

    if (n == 1) {
        x = Number.Two;
    }

    if (n == 2) {
        x = Number.Three;
    }

    if (n == 3) {
        x = Number.Four;
    }

    if (n == 4) {
        x = Number.Five;
    }

    return x;
}

pub fn main() !void {
    std.debug.warn("comptime getNum(0) == {}.\n", .{comptime getNum(0)});
    std.debug.warn("getNum(0) == {}.\n", .{getNum(0)});
}

>All comments

If the intention is to get the whole function to always run at compile time, then wrapping the body of the function in comptime { will give you a proper error:

.\5372.zig:19:15: error: unable to evaluate constant expression
        if (n == 0) {
              ^
.\5372.zig:15:32: note: referenced here
export fn getNum(n: u8) Number {
                               ^

As you have it written, it seems like a compile error is missing, though, since the docs say this:

In Zig, the programmer can label variables as comptime. This guarantees to the compiler that every load and store of the variable is performed at compile-time. Any violation of this results in a compile error.

Maybe something like:

value of comptime var depends on runtime value

Another possible fix for what you intended is to use comptime at the call site and remove it from inside the function:

const std = @import("std");

pub const Number = extern enum(u8) {
    Zero = 0,
    One = 1,
    Two = 2,
    Three = 3,
    Four = 4,
    Five = 5,
    Six = 6,
    Seven = 7,
    Eight = 8,
};

fn getNum(n: u8) Number {
    var x = Number.Zero;

    if (n == 0) {
        x = Number.One;
    }

    if (n == 1) {
        x = Number.Two;
    }

    if (n == 2) {
        x = Number.Three;
    }

    if (n == 3) {
        x = Number.Four;
    }

    if (n == 4) {
        x = Number.Five;
    }

    return x;
}

pub fn main() !void {
    std.debug.warn("comptime getNum(0) == {}.\n", .{comptime getNum(0)});
    std.debug.warn("getNum(0) == {}.\n", .{getNum(0)});
}
Was this page helpful?
0 / 5 - 0 ratings