# Clarification on comptime meta-programming

**URL:** <https://ziggit.dev/t/clarification-on-comptime-meta-programming/4346>\
**Category:** Explain\
**Tags:** language\
**Created:** [May 16, 2024, 9:59pm UTC](https://ziggit.dev/t/clarification-on-comptime-meta-programming/4346 "2024-05-16T21:59:04Z")\
**Posts on this page:** 5\
**Page:** 2

<div class="post-metadata">

**Author:** ![Tosti](https://ziggit.dev/letter_avatar_proxy/v4/letter/t/b38774/32.png) [@Tosti](https://ziggit.dev/u/Tosti)\
**Post date:** [May 17, 2024, 9:29pm UTC](https://ziggit.dev/t/clarification-on-comptime-meta-programming/4346/22 "2024-05-17T21:29:51Z")

</div>

> [@AndrewCodeDev](#):
>
> ```zig
> const std = @import("std");
> 
> fn decode_array_size(comptime string: []const u8) usize {
> // toy decoder - just add one everytime we see the letter 'a'
> comptime {
> var n: usize = 1;
> for (string) |char| {
> if (char == 'a') n += 1;
> }
> return n;
> }
> }
> 
> // later...
> const n = comptime decode_array_size("aaaaa");
> // notice this line - how is this possible?
> const array: [n]usize = undefined;
> 
> ```

I understand that this is a simple example, but I want to note that it’s not required to make the parameter and the function body `comptime`. Only the call site has to be `comptime`. This works as well.

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

fn decode_array_size(string: []const u8) usize {
    var n: usize = 1;
    for (string) |char| {
        if (char == 'a') n += 1;
    }
    return n;
}

pub fn main() void {
    const n = comptime decode_array_size("aaaaa");
    const array: [n]usize = undefined;
    _ = array;
}

```

So, in this case `decode_array_size` can be used both at runtime and comptime.

I think it is harmful to lock some functions behind redundant `comptime` when they very well may work at runtime too. It introduces additional contraint without any reason (as far as I can see).

---

<div class="post-metadata">

**Author:** ![AndrewCodeDev](https://ziggit.dev/letter_avatar_proxy/v4/letter/a/278dde/32.png) [@AndrewCodeDev](https://ziggit.dev/u/AndrewCodeDev)\
**Post date:** [May 17, 2024, 10:44pm UTC](https://ziggit.dev/t/clarification-on-comptime-meta-programming/4346/23 "2024-05-17T22:44:06Z")

</div>

> [@Tosti](#):
>
> It introduces additional contraint without any reason (as far as I can see).

It was definitely a weird example. I was intending to imply that this was something we only meant to do at comptime because the constraint is that you cannot set an array’s size at runtime with the value from that function (hence `decode_array_size`).

So I’ll meet you halfway here - there are functions that can be used meaningfully at runtime, absolutely - don’t wall those off behind a comptime block. If you intend to only make something run at comptime, then comptime blocks are a viable approach 👍

A better example that is more towards the original point (because again, that was kind of a weird example) would have been something like this within a comptime context:

```zig
comptime var n: usize = 1;
var array_1: [n]usize = undefined;
n += 1;
var array_2: [n]usize = undefined;
n += 1;
var array_3: [n]usize = undefined;

```

Because that actually makes the point I was driving at much better about the need for an allocator at comptime.

---

<div class="post-metadata">

**Author:** ![biosbob](https://ziggit.dev/user_avatar/ziggit.dev/biosbob/32/1987_2.png) [@biosbob](https://ziggit.dev/u/biosbob)\
**Post date:** [May 28, 2024, 12:52pm UTC](https://ziggit.dev/t/clarification-on-comptime-meta-programming/4346/24 "2024-05-28T12:52:01Z")

</div>

> [@AndrewCodeDev](#):
>
> ```zig
> const std = @import("std");
> 
> const Thing = struct {
> index: usize = 0,
> fn foo(comptime self: *Thing) void {
> if (comptime self.index < 3) {
> self.index += 1;
> return;
> }
> @compileError("Reached the end");
> }
> };
> 
> pub fn main() void {
> comptime {
> var thing: Thing = .{};
> thing.foo(); // fine...
> thing.foo(); // fine...
> thing.foo(); // fine...
> thing.foo(); // error
> }
> }
> 
> ```
> 
> Here we can see that `foo` has side effects, does not have the same behavior per input, and is run at comptime.

This is a great pattern. How might it look if we generalized it to a **hierarchy** where `ThingA` calls functions of `ThingB` and `ThingC`, and `ThingB` also uses `ThingC` ???

Presumably, `ThingA` could have fields of type `ThingB` and `ThingC`; and `ThingB` could likewise have a field of type `ThingC`. But don’t these fields really need to be `comptime` pointers to these structs??? Said another way, there is only one instance of `ThingC` whose state is manipulated by multiple clients.

The tricky part seems to be in generalizing the allocation of each of these `ThingX` objects within `main()`. But maybe it’s not so bad, since in my use-case I “know” the hierarchy is acyclic and hence can have a series of bottom-up `comptime var` declarations (starting with `ThingC`); the initializer for `ThingB` would wire-in a pointer to `ThingC`, which the initializer for `ThingA` would have pointers to `ThingB` and `ThingC`.

Given this hiearchy, `main()` simply “calls” on `ThingA` and the rest simply unfolds naturally. What I still don’t quite see, however, is how to implement one of the original questions at the very beginning of this post by @deckarep :

_What I’d like to do is have a function that can process some data using a datastructure, and build some kind of final, static result set at comptime. Then, at runtime my program uses the final result set._

How do I “freeze” the current value of the `index` field within my `ThingX` struct??? After a wave of `foo()` calls at each level of my hiearchy, I could certainly have a `freeze()` method called when `comptime` is finished, so to speak. Somehow I’ll need a `const` whose initializer depends upon the value of `index` at the time `freeze()` is called. I’m just not sure how to express this in Zig.

---

<div class="post-metadata">

**Author:** ![AndrewCodeDev](https://ziggit.dev/letter_avatar_proxy/v4/letter/a/278dde/32.png) [@AndrewCodeDev](https://ziggit.dev/u/AndrewCodeDev)\
**Post date:** [May 29, 2024, 5:23am UTC](https://ziggit.dev/t/clarification-on-comptime-meta-programming/4346/25 "2024-05-29T05:23:46Z")

</div>

In this instance, you’d freeze it like so:

```zig
comptime var thing: Thing = .{}; // make a thing
const frozen = thing; // freeze a thing

```

I read your example but some pseudo code may help me better understand what issue you are outlining.

---

<div class="post-metadata">

**Author:** ![biosbob](https://ziggit.dev/user_avatar/ziggit.dev/biosbob/32/1987_2.png) [@biosbob](https://ziggit.dev/u/biosbob)\
**Post date:** [May 29, 2024, 2:43pm UTC](https://ziggit.dev/t/clarification-on-comptime-meta-programming/4346/26 "2024-05-29T14:43:40Z")

</div>

Never mind the more complex example, here’s something simpler:

```zig
const Thing = struct {
    index: usize = 0,
    fn foo(comptime self: *Thing) void { self.index += 1; }
    fn bar(self: *Thing) void { //use "finalized" value of index }
};

pub fn main() void {
    comptime var thing: Thing = .{};
    comptime thing.foo();
        ...
    const frozen_thing = thing;
    frozen_thing.bar();
        ...
}

```

In this scenario, it appears that I’ve frozen the “entire” `Thing`. But what if I just want to freeze the `index` field as a constant, while having other `Thing` fields mutable at runtime via `bar()`???

Said another way, is it possible to implement a `Thing.freeze()` method which: 1) signals that there will be no more `comptime` method calls, and 2) that `Thing` itself should capture mutable fields like `index` into something that can no longer change.

Besides enforcing the “const-ness” of `index` at some point in time, one would also hope that the compiler would optimize accordingly.

Somewhat related, let’s assume that I have multiple `ThingX` types which will have just **ONE** instantiation in `main()`; that is to say, they’re singletons. Could I then implement this type using `const` and `var` declarations in lieu of fields – not unlike a top-level module container in its own source file???

[Previous page](https://ziggit.dev/t/clarification-on-comptime-meta-programming/4346.md?page=1)
