# Programmatically adding a const decl to a struct type at comptime

**URL:** <https://ziggit.dev/t/programmatically-adding-a-const-decl-to-a-struct-type-at-comptime/3959>\
**Category:** Help\
**Tags:** language\
**Created:** [April 15, 2024, 2:03am UTC](https://ziggit.dev/t/programmatically-adding-a-const-decl-to-a-struct-type-at-comptime/3959 "2024-04-15T02:03:46Z")\
**Posts on this page:** 10\
**Page:** 1

<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:** [April 15, 2024, 2:03am UTC](https://ziggit.dev/t/programmatically-adding-a-const-decl-to-a-struct-type-at-comptime/3959/1 "2024-04-15T02:03:46Z")

</div>

i want to write a generic function that takes a `struct S` as input and returns a `struct S'` as output, where `S'` has the same fields as `S` but with an additional `const` decl that i’ll reflect upon later as a “marker trait”…

to simplify the problem, assume `S` **only** has fields and no other decls… the types `S` and `S'` can also be “anonymous” specified as `struct { ... }`

presumably `@Type()` is involved in the answer, but the details elude me at this time…

---

<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:** [April 15, 2024, 5:44am UTC](https://ziggit.dev/t/programmatically-adding-a-const-decl-to-a-struct-type-at-comptime/3959/2 "2024-04-15T05:44:08Z")

</div>

This is a lot harder than adding fields. I was playing around with this and most of the options aren’t great. You can easily add a comptime `void` field to a struct and then check if you have it.

Essentially, `Declaration` leaves you pretty much abandoned at this point:

```zig
    /// This data structure is used by the Zig language code generation and
    /// therefore must be kept in sync with the compiler implementation.
    pub const Declaration = struct {
        name: [:0]const u8,
    };

```

While `StructField` gives you what you want:

```zig
    /// This data structure is used by the Zig language code generation and
    /// therefore must be kept in sync with the compiler implementation.
    pub const StructField = struct {
        name: [:0]const u8,
        type: type,
        default_value: ?*const anyopaque,
        is_comptime: bool,
        alignment: comptime_int,
    };

```

And if you try to add declarations using `@Type` then you’ll get this error:

```zig
main.zig:20:12: error: reified structs must have no decls

```

The thing is, I can add a comptime field to my struct through reification:

```zig
const S = struct {
    x: usize = 42, // of course  
};

pub fn MakeImportant(comptime T: type) type {

    const fields = @typeInfo(T).Struct.fields;

    comptime var new_fields: [fields.len + 1]std.builtin.Type.StructField = undefined;

    for (fields, 0..) |field, i| {
        new_fields[i] = field;
    }

    new_fields[fields.len] = .{
        .name = "important",
        .type = void,
        .default_value = &void{},
        .is_comptime = true,
        .alignment = 0,
    };
    
    return @Type(.{ .Struct = .{
        .layout = .auto,
        .fields = new_fields[0..],
        .decls = &.{},
        .is_tuple = false,
        .backing_integer = null,
    } });
}

pub fn main() !void {
    const s: MakeImportant(S) = .{};
    std.debug.print("is important: {}", .{ @hasField(@TypeOf(s), "important")});
}

```

And in this case, the size of the struct is still 8 - the size of its only `usize` member variable.

---

<div class="post-metadata">

**Author:** ![Sze](https://ziggit.dev/user_avatar/ziggit.dev/sze/32/496_2.png) [@Sze](https://ziggit.dev/u/Sze)\
**Post date:** [April 15, 2024, 9:39am UTC](https://ziggit.dev/t/programmatically-adding-a-const-decl-to-a-struct-type-at-comptime/3959/3 "2024-04-15T09:39:12Z")

</div>

> [@biosbob](#):
>
> where `S'` has the same fields as `S` but with an additional `const` decl that i’ll reflect upon later as a “marker trait”

I think @AndrewCodeDev is right that this isn’t easily possible, while I think the idea of using a zero sized field is valid and clever, it also feels a bit hacky to me.  
If there is generic code processing all fields that may also need to explicitly ignore the comptime field.

Here is what I would do instead.  
When `S` only has fields, you simply wrap `S` by making it a field in some other type.

```zig
const Wrapper = struct {
    s: S,

    pub const Important = true;
};

```

Then you can change your accessing code to access `wrapper.s` when `@TypeOf(x) == Wrapper`.  
But because only having a wrapper sometimes makes the access asymmetrical and thus more difficult, having to check types via comptime, you could instead have 2 different wrappers:

```zig
const Normal = struct {
    s: S,
    pub const Important = false;
};
const Special = struct {
    s: S,
    pub const Important = true;
}

```

Now you can just always use `wrapper.s` to unwrap the value und use `W.Important` to know if the value needs to be treated differently.  
If you have only one property you can just use the type of the wrapper instead of `Important`.

---

<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:** [April 15, 2024, 9:44am UTC](https://ziggit.dev/t/programmatically-adding-a-const-decl-to-a-struct-type-at-comptime/3959/4 "2024-04-15T09:44:30Z")

</div>

I think by the same token, we could just have a a function that has a comptime parameter type that also takes in a bool and returns another type:

```zig
pub fn AddStuff(comptime T: type, comptime stuff: bool) type {
    return struct {
        t: T,
        pub const stuff = stuff;
    };
}

```

That’s true about the extra field though - if you’re doing a lot of field processing, you could pick up that void field too. There isn’t a nice way to do this by my understanding.

---

<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:** [April 15, 2024, 1:36pm UTC](https://ziggit.dev/t/programmatically-adding-a-const-decl-to-a-struct-type-at-comptime/3959/5 "2024-04-15T13:36:14Z")

</div>

the solution proposed by @AndrewCodeDev certainly meets my needs…

in a language where duck-typing is emphasized – and the actual `@typeName` of some type is not always obvious – this is a great pattern for encoding comptime-discoverable “traits” than can be either explicitly or programmatically added to a `struct`…

my use-case will do lots of reflection; and these sorts of markers are relatively easy to spot using `@typeInfo` and `@hasField`…

bottom line – we discover objects programmatically by matching a “well-known name”, which in zig corresponds to a field of that name rather than some named type…

---

<div class="post-metadata">

**Author:** ![chung-leong](https://ziggit.dev/user_avatar/ziggit.dev/chung-leong/32/999_2.png) [@chung-leong](https://ziggit.dev/u/chung-leong)\
**Post date:** [April 15, 2024, 1:57pm UTC](https://ziggit.dev/t/programmatically-adding-a-const-decl-to-a-struct-type-at-comptime/3959/6 "2024-04-15T13:57:38Z")

</div>

Properly written code that deals with fields would check the `is_comptime` field before  
operating on them, so I don’t think that’s huge issue. Comptime field is a proper language feature. I think Sze got the impression that your solution is hacky only because you chose to put a `void` in there instead of, say, an anonymous struct.

---

<div class="post-metadata">

**Author:** ![Sze](https://ziggit.dev/user_avatar/ziggit.dev/sze/32/496_2.png) [@Sze](https://ziggit.dev/u/Sze)\
**Post date:** [April 15, 2024, 2:30pm UTC](https://ziggit.dev/t/programmatically-adding-a-const-decl-to-a-struct-type-at-comptime/3959/7 "2024-04-15T14:30:27Z")

</div>

Maybe it is just a way of signaling that I haven’t encountered often yet. Maybe it feels less hacky as you get more used to it.

Personally I haven’t had a need for it yet, maybe I need to keep the pattern in mind and see where it would make sense, to get more used to it. I think one thing that makes it kind of rare is that because you can’t create your own declarations for types created with `@Type`, I tend to avoid mixing complexity with types created via `@Type` and instead put the complexity in a type that just wraps around it.

When you can’t really attach methods etc. to the created type it doesn’t seem that helpful to add marker const declarations to it, but maybe I just haven’t encountered particular uses of the feature.

So far my use of comptime fields was mostly as tuples. Not really mixing run-time fields with comptime fields a whole lot.

---

<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:** [April 15, 2024, 2:56pm UTC](https://ziggit.dev/t/programmatically-adding-a-const-decl-to-a-struct-type-at-comptime/3959/8 "2024-04-15T14:56:18Z")

</div>

to your point, “reification” of structs can’t add decls anyway (as pointed out earlier in this thread)…

since my use of these marker fields is sometimes explicit and sometimes done programmatically, at least i’m consistent!!!

for the sort of very rich duck-typing i anticipate using, this technique allows me to perform an extra level of semantic checking beyond what i can overtly express in the base zig type system…

---

<div class="post-metadata">

**Author:** ![nyc](https://ziggit.dev/user_avatar/ziggit.dev/nyc/32/1167_2.png) [@nyc](https://ziggit.dev/u/nyc)\
**Post date:** [April 15, 2024, 3:12pm UTC](https://ziggit.dev/t/programmatically-adding-a-const-decl-to-a-struct-type-at-comptime/3959/9 "2024-04-15T15:12:34Z")

</div>

> [@Sze](#):
>
> I tend to avoid mixing complexity with types created via `@Type` and instead put the complexity in a type that just wraps around it.

I tried this for padding a struct to a cache line. I had a wrapper:

```zig
pub fun Padded(comptime Inner: type) type {
  return extern struct { 
    // usingnamespace Inner; // tried this too
    const __pad_size = pad_to_amount(64, @sizeOf(Inner));
    d: Inner,
     __pad: [__pad_size]u8 = [_]u8{0} ** __pad_size,
    pub fn init_padded() @This() {
      return .{.d=Inner.init()};
    }
  };
}

```

and it was a disaster that I had to roll back. The code became so confusing. I tried adding `usingnamespace Inner` to it too, but still horrible. All the accessing code was `var.d.insidevar.init().d.etc...`. It make the code difficult to write and horrible to try to read. I went back to doing everything by hand. The old way of usingnamespace would have eliminated all of that. The wrapper struct get unmanageable so fast.

---

<div class="post-metadata">

**Author:** ![nyc](https://ziggit.dev/user_avatar/ziggit.dev/nyc/32/1167_2.png) [@nyc](https://ziggit.dev/u/nyc)\
**Post date:** [April 15, 2024, 3:23pm UTC](https://ziggit.dev/t/programmatically-adding-a-const-decl-to-a-struct-type-at-comptime/3959/10 "2024-04-15T15:23:45Z")

</div>

I wrote some comptime functions that check to see if one type is supertype of another where supertype is deifned as having all pub decls and fields of another but not just limited to those. I can then write an interface struct (yeah each function needs a body still but I make it just a simple return of whatever – it never gets run just needs to be there syntactically) and reference it in the documentation so show what fn signatures, decls, and fields need to be implemented. And the first line of the any function taking an anytype can do a full typechecl.

The hashmap has this very very long hand written highly specific verifyContext function. I’m not sure why that wasn’t just written generically and added to meta. Everybody with their own bespoke implementations is really bad for the langauge.

I added a `const __implOf: type = InterfaceType` so the interface checker can recursive check all types in consistent with their interfaces. There is a problem right now with mutually recursive types, and either use the void trick or just make comptime array of all the types I’ve seen and just keep adding to that and looking them up or some other way to stop the recursion. (I use \_\_ as a prefix to items that signaling or autogenerated).
