How can I check if a function parameter is a comptime parameter?

fn do() !void {
  const str = random_str();
  try checkPara("hello"); // this is comptime
  try checkPara(str); // this is runtime
}
fn checkPara(para: []const u8) !void {
  if(para_is_comptime) { // how to impl?
    checkParaWithComptime(para);
  } else {
    try checkParaWithRuntime(para);
  }
}
fn checkParaWithComptime(comptime para: []const u8) void {
  if(para.len == 0) @compileError("para is empty");
}
fn checkParaWithRuntime(para: []const u8) !void {
  if(para.len == 0) return error.ParaEmpty;
}

Pretty cursed but does the job. You need to make function inline or else it won’t try to be executed at comptime.

pub fn main() !void {
    var empty_runtime_known = "";
    _ = &empty_runtime_known;
    const empty_comptime_known = "";
    var nonempty_runtime_known = "hello";
    _ = &nonempty_runtime_known;
    const nonempty_comptime_known = "hello";

    try checkPara(nonempty_comptime_known); // this is comptime

    try checkPara(empty_comptime_known); // this line failes to compile

    try checkPara(nonempty_runtime_known); // this is runtime
    try checkPara(empty_runtime_known); // this is runtime
}

inline fn checkPara(para: anytype) !void {
    const s = .{ .a = para };
    if (@typeInfo(@TypeOf(s)).@"struct".fields[0].is_comptime) {
        comptime checkParaWithComptime(para);
    } else {
        try checkParaWithRuntime(para);
    }
}
fn checkParaWithComptime(comptime para: []const u8) void {
    if (comptime para.len == 0) @compileError("para is empty");
}
fn checkParaWithRuntime(para: []const u8) !void {
    if (para.len == 0) return error.ParaEmpty;
}
5 Likes

Oh, this is useful, but not natural at all. It would be great if there were a built-in function @isComptimeVar(xxx) or std.meta.isComptime(xxx).

If your usecase is simply validating something why not use the comptime keyword instead of adding logic that’s specific to comptime?

fn validate([]const u8) !void { return error.Unimplemented; }

try validate(params);
// or comptime
comptime validate("param") catch unreachable;
3 Likes

The main disadvantage I see in this is that you lose the @compileError message. Using @inComptime can help here, but you still have to use comptime on the function call, even if the arguments are statically known.

pub fn main() !void {
    try validateEven(1); // Will fail at runtime with error: NotEven
    comptime try validateEven(1); // Will fail to compile with error: not even!
}

fn validateEven(x: usize) !void {
    if (x % 2 != 0) {
        if (@inComptime()) {
            @compileError("not even!");
        }
        return error.NotEven;
    }
}

Some people misunderstood my intention, I just wanted to decouple the comptime and runtime attributes of function parameters, allowing them to diverge into two separate paths.

You have been given multiple solutions for that, depending on your exact needs.

this is based on the whole function call being comptime or not.

And this is for individual parameters comptime-ness.

I very much prefer for the function to not care about this at all, and let the caller deal with whether or not it wants comptime, but that isnt practicall if you only want to apply this to some parameters.

2 Likes