# Generate functions during comptime

**URL:** <https://ziggit.dev/t/generate-functions-during-comptime/10921>\
**Category:** Help\
**Tags:** language\
**Created:** [July 11, 2025, 6:11pm UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921 "2025-07-11T18:11:41Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![ww520](https://ziggit.dev/letter_avatar_proxy/v4/letter/w/c2a13f/32.png) [@ww520](https://ziggit.dev/u/ww520)\
**Post date:** [July 11, 2025, 6:11pm UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/1 "2025-07-11T18:11:41Z")

</div>

Is it possible to generate functions during comptime? The following code attempts to generate the getter functions of a struct (not that I need getters, just an example). It has problem at `@field(S, getter_name)`.

```zig

const User = struct {
    name: []const u8,
    age: u32,

    comptime {
        generateGetters(@This());
    }
};

fn generateGetters(comptime S: type) void {
    const info = @typeInfo(S).@"struct";

    inline for (info.fields) |field| {
        // Generate getter
        const getter_name = "get_" ++ field.name;
        fn @field(S, getter_name)(self: *const S) field.type {
            return @field(self, field_name);
        }
    }
}

```

---

<div class="post-metadata">

**Author:** ![cryptocode](https://ziggit.dev/user_avatar/ziggit.dev/cryptocode/32/817_2.png) [@cryptocode](https://ziggit.dev/u/cryptocode)\
**Post date:** [July 11, 2025, 6:34pm UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/2 "2025-07-11T18:34:42Z")

</div>

That’s not valid syntax. Generating functions at comptime (beyond anytype monomorphization) is not possible. You’d have to do it through code generations, such as via the build system. Also worth noting that getters/setters isn’t really idiomatic Zig, though maybe you were just using that as an example.

Here’s a good read: [https://matklad.github.io/2025/04/19/things-zig-comptime-wont-do.html](https://matklad.github.io/2025/04/19/things-zig-comptime-wont-do.html)

---

<div class="post-metadata">

**Author:** ![ForeverZer0](https://ziggit.dev/user_avatar/ziggit.dev/foreverzer0/32/2443_2.png) [@ForeverZer0](https://ziggit.dev/u/ForeverZer0)\
**Post date:** [July 11, 2025, 7:19pm UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/3 "2025-07-11T19:19:53Z")

</div>

As already noted, this is not possible with Zig, at least using the way that you are might be used to doing it other languages.

However, there are projects that accomplish the same end result using the build system, which can be used to generate source code, import it into a module, and then use it within your project.

Some notable examples that your might find interesting:

- [zig-wayland](https://codeberg.org/ifreund/zig-wayland)
- [zigglgen](https://github.com/castholm/zigglgen)

Each of these doesn’t come with actual code, you configure them in your build script, generate, then `@import` and use them normally.

However, none of these will add functions scoped under existing types like in your example.

---

<div class="post-metadata">

**Author:** ![jbe](https://ziggit.dev/letter_avatar_proxy/v4/letter/j/f6c823/32.png) [@jbe](https://ziggit.dev/u/jbe)\
**Post date:** [July 11, 2025, 7:27pm UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/4 "2025-07-11T19:27:16Z")

</div>

What I noticed is that it’s not possible to do stuff like

```zig
const SomeType = struct {
    pub fn someMethod(self: SomeType) void { /* ... */ }
    pub fn someOtherMethod(self: SomeType) void { /* ... */ }
    // a lot of other methods
};
const SomeOtherType = struct {
    inner_value: SomeType,
    // It doesn't work to automatically make all methods of
    // `SomeType` available here.
};

```

I guess that’s the reason why we often see things like:

_(edit: This is not idiomatic, see response below.)_

```zig
const SomeOtherType = struct {
    inner_value: SomeType,
    pub fn some(self: SomeOtherType) SomeType {
        return inner_value;
    }
};

```

Such that you can write:

```zig
some_other_value.some().someMethod();

```

Methods like [`std.fs.File.writer`](https://ziglang.org/documentation/0.14.1/std/#std.fs.File.writer) feel similar to that pattern: A `File` will _not_ act like a `Writer` but you must obtain a writer through a method.

(Not sure if I observed that right.)

Anyway, I’m amazed how Zig manages providing a lot of reflection and enabling generic programming nonetheless (e.g. allowing implementation of the `print` functions) in Zig.

The minimalism somehow reminds me of (typical coding in) Lua, even though Lua only works at runtime in this matter, while Zig can perform monomorphization at compile time.

---

<div class="post-metadata">

**Author:** ![ForeverZer0](https://ziggit.dev/user_avatar/ziggit.dev/foreverzer0/32/2443_2.png) [@ForeverZer0](https://ziggit.dev/u/ForeverZer0)\
**Post date:** [July 11, 2025, 7:48pm UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/5 "2025-07-11T19:48:47Z")

</div>

```zig
const SomeOtherType = struct {
    inner_value: SomeType,
    pub fn some(self: SomeOtherType) SomeType {
        return inner_value;
    }
};

```

This use of getters/setters is not idiomatic Zig, which would simply access the field directly. This is not a pattern you should use in Zig unless it is to fulfill some interface requirement.

The distinction should be made, using your example, that the use of `writer()` functions are not just to be a getters, but to wrap the field into an interface.

---

<div class="post-metadata">

**Author:** ![ww520](https://ziggit.dev/letter_avatar_proxy/v4/letter/w/c2a13f/32.png) [@ww520](https://ziggit.dev/u/ww520)\
**Post date:** [July 12, 2025, 8:08am UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/6 "2025-07-12T08:08:40Z")

</div>

Thanks for all the information. It’s really helpful.

---

<div class="post-metadata">

**Author:** ![jbe](https://ziggit.dev/letter_avatar_proxy/v4/letter/j/f6c823/32.png) [@jbe](https://ziggit.dev/u/jbe)\
**Post date:** [July 12, 2025, 9:42am UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/7 "2025-07-12T09:42:01Z")

</div>

> [@cryptocode](#):
>
> Generating functions at comptime (beyond anytype monomorphization) is not possible.

I tried to challenge this (to some extent) with a bit of syntax gymnastics 🏋️‍♂️:

```zig
const std = @import("std");

pub fn dispatch(comptime name: []const u8, args: anytype) void {
    _ = args;
    comptime var is_foo: bool = undefined;
    comptime var is_test: bool = undefined;
    comptime var suffix: i32 = undefined;
    comptime success: {
        is_foo = std.mem.startsWith(u8, name, "foo");
        if (is_foo) {
            suffix = std.fmt.parseInt(i32, name[3..], 0) catch {
                @compileError("Tried to call unknown function");
            };
            if (suffix < 0 or suffix >= 10000) {
                @compileError("Tried to call unknown function");
            }
            break :success;
        }
        is_test = std.mem.startsWith(u8, name, "test");
        if (is_test) {
            suffix = std.fmt.parseInt(i32, name[4..], 0) catch {
                @compileError("Tried to call unknown function");
            };
            if (suffix < 0 or suffix >= 100) {
                @compileError("Tried to call unknown function");
            }
            break :success;
        }
        @compileError("Tried to call unknown function");
    }
    if (is_foo) {
        std.debug.print(
            "Called foo function with suffix {}.\n",
            .{suffix},
        );
    } else if (is_test) {
        std.debug.print(
            "Called testing function with suffix {}.\n",
            .{suffix},
        );
    } else unreachable;
}

pub fn main() void {
    dispatch("foo12", .{});
    dispatch("test12", .{});
    dispatch("foo3745", .{});
    //dispatch("test3745", .{}); // try to uncomment me
}

```

This generates effectively 10100 possible “functions” (not really functions, but things you can call with `dispatch("some_function_name", .{})`):

- `foo0` to `foo9999`
- `test0` to `test99`

(plus equivalents with leading zeros)

Output:

```plaintext
Called foo function with suffix 12.
Called testing function with suffix 12.
Called foo function with suffix 3745.

```

Uncommenting the last line then results, expectedly, in:

```zig
comptimefunc.zig:25:17: error: Tried to call unknown function
                @compileError("Tried to call unknown function");
                ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
referenced by:
    main: comptimefunc.zig:48:13
    callMain [inlined]: /home/jbe/lib/zig/std/start.zig:666:22
    callMainWithArgs [inlined]: /home/jbe/lib/zig/std/start.zig:635:20
    main: /home/jbe/lib/zig/std/start.zig:650:28
    1 reference(s) hidden; use '-freference-trace=5' to see all references

```

Thus reporting a compile-time error, demonstrating that dispatching is indeed done at compile time, right?

Not sure if this is useful for anything.

---

<div class="post-metadata">

**Author:** ![cryptocode](https://ziggit.dev/user_avatar/ziggit.dev/cryptocode/32/817_2.png) [@cryptocode](https://ziggit.dev/u/cryptocode)\
**Post date:** [July 12, 2025, 9:54am UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/8 "2025-07-12T09:54:31Z")

</div>

> [@jbe](#):
>
> > [@cryptocode](#):
> >
> > Generating functions at comptime (beyond anytype monomorphization) is not possible.
> 
> I tried to challenge this (to some extent) with a bit of syntax gymnastics 🏋️‍♂️:

That is still just monomorphization 😉

```zig
$ nm ./dispatch | rg dispatch
000000010009ecd0 t _mono.dispatch__anon_19578
000000010009ece4 t _mono.dispatch__anon_19583
000000010009ecf8 t _mono.dispatch__anon_19588

```

---

<div class="post-metadata">

**Author:** ![koe](https://ziggit.dev/user_avatar/ziggit.dev/koe/32/9493_2.png) [@koe](https://ziggit.dev/u/koe)\
**Post date:** [July 12, 2025, 10:24am UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/9 "2025-07-12T10:24:19Z")

</div>

I have been curious if it is at all planned to add actual support for this. And if not, why not?

I know generating structs at comptime is possible, to my naive mind it seems arbitrary to not support comptime function generation.

---

<div class="post-metadata">

**Author:** ![jbe](https://ziggit.dev/letter_avatar_proxy/v4/letter/j/f6c823/32.png) [@jbe](https://ziggit.dev/u/jbe)\
**Post date:** [July 12, 2025, 11:40am UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/10 "2025-07-12T11:40:52Z")

</div>

> [@cryptocode](#):
>
> That is still just monomorphization 😉

Well, yeah, but…

> [@cryptocode](#):
>
> (beyond anytype monomorphization)

… it doesn’t involve `anytype` at least. So I guess it’s notable that this form of comp-time dispatching doesn’t need **`anytype`** , i.e. the dispatching at compile time isn’t done using types, but using an identifier (the “name” of that “function-like-thing”).

(Sorry I don’t have better terminiology.)

---

<div class="post-metadata">

**Author:** ![cryptocode](https://ziggit.dev/user_avatar/ziggit.dev/cryptocode/32/817_2.png) [@cryptocode](https://ziggit.dev/u/cryptocode)\
**Post date:** [July 12, 2025, 11:48am UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/11 "2025-07-12T11:48:43Z")

</div>

> [@jbe](#):
>
> it doesn’t involve `anytype` at least.

Sure including anytype in that statement was imprecise, but monomorphization is what happens here because of the comptime parameter

---

<div class="post-metadata">

**Author:** ![jbe](https://ziggit.dev/letter_avatar_proxy/v4/letter/j/f6c823/32.png) [@jbe](https://ziggit.dev/u/jbe)\
**Post date:** [July 12, 2025, 12:59pm UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/12 "2025-07-12T12:59:40Z")

</div>

I think in Rust this is what’s called [`Const generics`](https://doc.rust-lang.org/reference/items/generics.html#const-generics) there.

But what I like about Zig is that there is no distinction between whether we distinguish by `type` or `[]const u8` here, as types are “just” values (as far as I understand). So the same feature/syntax serves monomorphization based on types and monomorphization based on values.

Maybe there are some more differences between Rust and Zig here. For example, restricting a const param would be done through a `where` clause in Rust, I think, while in Zig it’s simply done in the function body using “normal” Zig syntax:

> ```zig
> if (suffix < 0 or suffix >= 10000) {
> @compileError("Tried to call unknown function");
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![jbe](https://ziggit.dev/letter_avatar_proxy/v4/letter/j/f6c823/32.png) [@jbe](https://ziggit.dev/u/jbe)\
**Post date:** [July 12, 2025, 1:30pm UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/13 "2025-07-12T13:30:02Z")

</div>

> [@ww520](#):
>
> (not that I need getters, just an example)

Taking your example (acknowledging that it is in Zig getters are _not idiomatic_, just following that example here), and using `comptime` arguments, it would be possible to do:

```zig
const std = @import("std");

const User = struct {
    name: []const u8,
    age: u32,
    pub fn get(
        self: User,
        comptime field: []const u8,
    ) @FieldType(User, field) {
        std.debug.print("Reading field \"{s}\".\n", .{field});
        return @field(self, field);
    }
};

pub fn main() void {
    const user = User{ .name = "Alice", .age = 34 };
    std.debug.print("User {s}, age {}.\n", .{
        user.get("name"),
        user.get("age"),
    });
}

```

Output:

```plaintext
Reading field "name".
Reading field "age".
User Alice, age 34.

```

> [@koe](#):
>
> I have been curious if it is at all planned to add actual support for this. And if not, why not?

I don’t know, but I wonder if it’s really needed, given that Zig seems to be quite powerful already as is. Maybe you have a specific use-case in mind?

---

<div class="post-metadata">

**Author:** ![Calder-Ty](https://ziggit.dev/user_avatar/ziggit.dev/calder-ty/32/10237_2.png) [@Calder-Ty](https://ziggit.dev/u/Calder-Ty)\
**Post date:** [July 12, 2025, 1:34pm UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/14 "2025-07-12T13:34:04Z")

</div>

> [@jbe](#):
>
> But what I like about Zig is that there is no distinction between whether we distinguish by `type` or `[]const u8` here, as types are “just” values (as far as I understand). So the same feature/syntax serves monomorphization based on types and monomorphization based on values.

I’d say that the key point here is when the parameters to the function are known. Types are values _only_ at compiletime. They don’t exist after compiletime. Because your `[] const u8` is compiletime known it gets the same ‘monomorphization’ treatment.

---

<div class="post-metadata">

**Author:** ![jbe](https://ziggit.dev/letter_avatar_proxy/v4/letter/j/f6c823/32.png) [@jbe](https://ziggit.dev/u/jbe)\
**Post date:** [July 12, 2025, 2:26pm UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/15 "2025-07-12T14:26:20Z")

</div>

> [@Calder-Ty](#):
>
> Types are values _only_ at compiletime.

Oh, I didn’t realize that. Interesting!

I tried:

```zig
const std = @import("std");

pub fn foo(t: type) void {
    std.debug.print("{}", .{t != void});
}

pub fn main() void {
    for (0..10) |_| {
        const b = std.crypto.random.float(f64) < 0.4;
        foo(if (b) i32 else void);
    }
}

```

And indeed I get:

```zig
type.zig:10:13: error: value with comptime-only type 'type' depends on runtime control flow
        foo(if (b) i32 else void);
            ^ ~~~~~~~~~~~~~~~~~~~
type.zig:8:10: note: runtime control flow here
    for (0..10) |_| {
         ^ ~~~~
type.zig:10:13: note: types are not available at runtime
referenced by:
    callMain [inlined]: /home/jbe/lib/zig/std/start.zig:672:22
    callMainWithArgs [inlined]: /home/jbe/lib/zig/std/start.zig:641:20
    main: /home/jbe/lib/zig/std/start.zig:656:28
    1 reference(s) hidden; use '-freference-trace=4' to see all references

```

Thanks to have pointed that out.

---

<div class="post-metadata">

**Author:** ![koe](https://ziggit.dev/user_avatar/ziggit.dev/koe/32/9493_2.png) [@koe](https://ziggit.dev/u/koe)\
**Post date:** [July 12, 2025, 2:26pm UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/16 "2025-07-12T14:26:37Z")

</div>

One use case I ran into was making a machine learning runtime that create a struct for a model containing its weights. The issue arose when automatically generating the “run” function for said struct, which had to invoke a series of predetermined helper functions.

I don’t recall right now how I got around this, I think there is a way as you say!

---

<div class="post-metadata">

**Author:** ![jbe](https://ziggit.dev/letter_avatar_proxy/v4/letter/j/f6c823/32.png) [@jbe](https://ziggit.dev/u/jbe)\
**Post date:** [July 12, 2025, 2:38pm UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/17 "2025-07-12T14:38:31Z")

</div>

> [@jbe](#):
>
> > [@Calder-Ty](#):
> >
> > Types are values _only_ at compiletime.
> 
> Oh, I didn’t realize that. Interesting!

Question: Does that mean that `comptime` before some `t: type` argument is superfluous, and just a matter of good coding style? (I.e. it doesn’t make a difference whether you write `comptime` before a `type` argument?)

---

<div class="post-metadata">

**Author:** ![Calder-Ty](https://ziggit.dev/user_avatar/ziggit.dev/calder-ty/32/10237_2.png) [@Calder-Ty](https://ziggit.dev/u/Calder-Ty)\
**Post date:** [July 12, 2025, 3:36pm UTC](https://ziggit.dev/t/generate-functions-during-comptime/10921/18 "2025-07-12T15:36:12Z")

</div>

yes, comptime is not necessary there. It used to be required I believe, but with types that requirement was relaxed.
