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
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).
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));
}
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:
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.
Things would be a lot simpler if all functions can be executed at comptime. Just saying.
We can then safely rename comptime to runtime.