Assert code can be executed at compile time

Is there a way to ensure that a function can be run at compile time (something like C++'s constexpr keyword)?

Hello @anon13358180
welcome to ziggit :slight_smile:

comptime is a keyword that declares expressions, function parameters and variables as compile time.

To ensure that a function runs at compile time, include its call in a comptime expression.

Example:

comptime {
    func_call();
}

In the example, the comptime expression guarantees that the func_call will be evaluated at compile-time. The comptime expression can be placed wherever an expression is valid (e.g. in a function, or as a constant or variable initialization).

2 Likes

I want to ensure that a function can be run at compile time. For example I have this code snippet

const Token = struct {
-- snip --
    pub fn charCount(self: @This()) usize {
        return switch (self) {
            .left_paren,
            .right_paren,
            .left_brace,
            .right_brace,
            .plus,
            .dash,
            .star,
            .slash,
            .comma,
            .semicolon,
            .bang,
            .equal,
            .greater,
            .less,
            => 1,

            .bang_equal,
            .double_equal,
            .greater_equal,
            .less_equal,
            .if_,
            .do,
            => 2,

            .end => 3,

            .number, .identifier => |string| string.len,
            .string => |string| string.len + 2,
        };
    }
}

I wanted to be able to ensure that this code doesn’t depend on any runtime execution (IO, dynamic memory, etc), similar to functional purity.

Although based on your response I’m going to assume the answer is no.

Between return and switch you can put comptime. This implies that self is also comptime. But is this possible? Isn’t self constructed at runtime?

    pub fn charCount(comptime self: @This()) usize {
        return comptime switch (self) {
    ...

Yes Token is constructed at runtime. I wanted to do was ensure that the function is able to be run at compile time. I was cleaning up my code base to try and separate the logic and state as much as possible.

The only way to ensure that a function may be run at comptime (and not insist that it must be run at comptime), is to call it using comptime.


fn maybeComptime(a: usize, b: usize) usize {
    return a + b;
}

test "comptime callable?" {
    // It can be called at comptime
    try expectEqual(10, comptime maybeComptime(5, 5));
    // And at runtime
    var b: usize = 5; // var ensures runtime
    _ = &b; // This makes the compiler not complain about mutation
    try expectEqual(10, maybeComptime(b, b));
    // This would give error: unable to resolve comptime value
    // try expectEqual(10, comptime maybeComptime(b, b));
}
4 Likes

A slight permutation on this same idea is to put the tests in a function and then call the function at runtime and comptime in a test block. This is common in the std.math tests, for example:

6 Likes

comptime is present in the error message, but is missing in the code. The code shode be

try expectEqual(10, comptime maybeComptime(b, b));

I was referring to the commented-out line below it, which is indeed identical to what you posted.

When I post things in test form, I try to make it so that they run. If there’s something which won’t compile, I leave it as a comment, so that anyone can paste the test into a zig file and run the test, then un-comment the line and see the error for themselves.

I see. Agree, makes sense. Unfortunately, there are no comptime checks whether something compiles currently. They could be useful here.

1 Like

Things would be a lot simpler if all functions can be executed at comptime. Just saying.

1 Like

We can then safely rename comptime to runtime.