# Programmatically creating an interface table for a set of implementation fxns

**URL:** <https://ziggit.dev/t/programmatically-creating-an-interface-table-for-a-set-of-implementation-fxns/5342>\
**Category:** Help\
**Tags:** language, comptime\
**Created:** [July 25, 2024, 12:44am UTC](https://ziggit.dev/t/programmatically-creating-an-interface-table-for-a-set-of-implementation-fxns/5342 "2024-07-25T00:44:36Z")\
**Posts on this page:** 9\
**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:** [July 25, 2024, 12:44am UTC](https://ziggit.dev/t/programmatically-creating-an-interface-table-for-a-set-of-implementation-fxns/5342/1 "2024-07-25T00:44:36Z")

</div>

i would like to automatically “reify” a struct type whose fields are pointers to functions implemented within another container… said another way, i’m trying to write a generic function that encapsulates the “function-pointer-table” design pattern commonly used when implementing abstract interfaces…

here’s my current attempt:

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

const print = std.log.debug;

const Impl = struct {
    pub fn foo(x: u32) void {
        print("foo({d})", .{x});
    }
    pub fn bar() void {
        print("bar", .{});
    }
};

fn ItabFrom(T: type) type {
    const ti = @typeInfo(T);
    comptime var fld_list: []const std.builtin.Type.StructField = &.{};
    inline for (ti.Struct.decls) |d| {
        const dval = @field(T, d.name);
        const dti = @typeInfo(@TypeOf(dval));
        if (dti == .Fn) {
            const FT = @Type(.{ .Pointer = .{
                .size = .One,
                .is_const = true,
                .is_volatile = false,
                .alignment = 1,
                .address_space = .generic,
                .child = @TypeOf(dval),
                .is_allowzero = false,
                .sentinel = null,
            } });
            const fld = std.builtin.Type.StructField{
                .name = d.name,
                .type = FT,
                .default_value = dval,
                .is_comptime = false,
                .alignment = 0,
            };
            fld_list = fld_list ++ ([_]std.builtin.Type.StructField{fld})[0..];
        }
    }
    const IT = @Type(.{ .Struct = .{
        .layout = .auto,
        .fields = fld_list,
        .decls = &.{},
        .is_tuple = false,
        .backing_integer = null,
    } });
    return IT;
}

pub fn main() void {
    const IT = ItabFrom(Impl);
    print("size = {d}", .{@sizeOf(IT)});
}

```

but here’s the output i receive when compiling this program (under 0.12.0):

```zig
src\main.zig:42:16: error: comptime dereference requires 'fn (u32) void' to have a well-defined layout
    const IT = @Type(.{ .Struct = .{
               ^ ~~~~
src\main.zig:53:24: note: called from here
    const IT = ItabFrom(Impl);
               ~~~~~~~~^~~~~~

```

my goal is for this synthesized struct to effectively match the following **explicitly** defined struct (which i could tediously write by hand):

```zig
const Impl = struct {
    foo: *const fn (u32) void = &Impl.foo,
    bar: *const fn () void = &Impl.bar,
};

```

my use-case is somewhat simpler than the “classic vtable”, in that my functions do _NOT_ have a `self` parameter; no need to carry around an opaque ptr in the interface struct…

---

<div class="post-metadata">

**Author:** ![purefns](https://ziggit.dev/user_avatar/ziggit.dev/purefns/32/3018_2.png) [@purefns](https://ziggit.dev/u/purefns)\
**Post date:** [July 25, 2024, 12:56am UTC](https://ziggit.dev/t/programmatically-creating-an-interface-table-for-a-set-of-implementation-fxns/5342/2 "2024-07-25T00:56:48Z")

</div>

Not sure if this is what you’re looking for, but I got a lot of value out of the article [Interfaces, or: Runtime Polymorphism in Zig](https://www.nmichaels.org/zig/interfaces.html) - specifically, I think this snippet from it might be useful to you:

```zig
/// Iterators can be iterated with while loops. The next
/// function returns null when the iterator is exhausted.
pub fn Iterator(comptime T: type) type {
    return struct {
        const Self = @This();
        nextFn: fn (self: *Self) ?T,
        resetFn: fn (self: *Self) void,
        pub fn next(self: *Self) ?T {
            return self.nextFn(self);
        }
        pub fn reset(self: *Self) void {
            return self.resetFn(self);
        }
    };
}

```

Like you were looking for, there is no `anyopaque` pointer needed, just function pointers. Sorry if I’m totally off-base here though!

---

<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:** [July 25, 2024, 1:29am UTC](https://ziggit.dev/t/programmatically-creating-an-interface-table-for-a-set-of-implementation-fxns/5342/3 "2024-07-25T01:29:19Z")

</div>

Edited: See my updated answer - [Programmatically creating an interface table for a set of implementation fxns - #5 by AndrewCodeDev](https://ziggit.dev/t/programmatically-creating-an-interface-table-for-a-set-of-implementation-fxns/5342/5)

The problem here looks like the `*const F` instead of just `F`. You can get past this as direct function types because it looks like the pointer-to-function is expecting well defined layout. You can do this:

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

const print = std.log.debug;

const Impl = struct {
    pub fn foo(x: u32) void {
        print("foo({d})", .{x});
    }
    pub fn bar() void {
        print("bar", .{});
    }
};

fn ItabFrom(T: type) type {
    comptime {
        const TI = @typeInfo(T);
    
        const decls = TI.Struct.decls;
    
        var fld_list: [decls.len]std.builtin.Type.StructField = undefined;
    
        for (decls, 0..) |decl, i| {
    
            const func = @field(T, decl.name);
            
            fld_list[i] = std.builtin.Type.StructField{
                .name = decl.name,
                .type = @TypeOf(func),
                .default_value = func,
                .is_comptime = false,
                .alignment = 0,
            };
        }
    
        const freeze = fld_list;
    
        return @Type(.{ .Struct = .{
            .layout = .auto,
            .fields = freeze[0..],
            .decls = &.{},
            .is_tuple = false,
            .backing_integer = null,
        }});
    }
}

pub fn main() void {
    const itab = ItabFrom(Impl){};
    itab.bar();
}

```

Essentially, we’re transforming declarations into member fields and using those instead. At this level, I’m not sure what advantage you’d get by having a `*const F` as oppsed to the direct function type. Either way, when you remove the pointer qualifier, you’ll see that it works.

---

<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:** [July 25, 2024, 1:31am UTC](https://ziggit.dev/t/programmatically-creating-an-interface-table-for-a-set-of-implementation-fxns/5342/4 "2024-07-25T01:31:36Z")

</div>

Now, what you may be trying to do is construct a generic interface from a set of struct decls. I don’t see why that can’t be done using the same technique. At some level, I just throw up my hands and say “where’s the duck when you need him?”

---

<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:** [July 25, 2024, 1:57am UTC](https://ziggit.dev/t/programmatically-creating-an-interface-table-for-a-set-of-implementation-fxns/5342/5 "2024-07-25T01:57:04Z")

</div>

Okay, @biosbob, this actually works for the `*const F` - I do this by distinguishing between reification and initialization here and I do that through another indirection. In short, I don’t see a way to do it through direct reification, but if you can stomach assignments via an `inline for` then this should do it for you:

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

const print = std.log.debug;

const Impl = struct {
    pub fn foo(x: u32) void {
        print("foo({d})", .{x});
    }
    pub fn bar() void {
        print("bar", .{});
    }
};

fn ItabType(T: type) type {
    comptime {
        const TI = @typeInfo(T);
    
        const decls = TI.Struct.decls;
    
        var fld_list: [decls.len]std.builtin.Type.StructField = undefined;
    
        for (decls, 0..) |decl, i| {
    
            const func = @field(T, decl.name);
            
            fld_list[i] = std.builtin.Type.StructField{
                .name = decl.name,
                .type = *const @TypeOf(func),
                .default_value = null,
                .is_comptime = false,
                .alignment = 0,
            };
        }
    
        const freeze = fld_list;
    
        return @Type(.{ .Struct = .{
            .layout = .auto,
            .fields = freeze[0..],
            .decls = &.{},
            .is_tuple = false,
            .backing_integer = null,
        }});
    }
}

pub fn initItab(comptime impl: type) ItabType(impl) {

    var itab: ItabType(impl) = undefined;

    inline for (comptime std.meta.declarations(impl)) |decl| {
        @field(itab, decl.name) = @field(impl, decl.name);
    }

    return itab;
}

pub fn main() void {
    const itab = initItab(Impl);
    itab.bar();
}

```

What’s even funnier here is that this also works using a comptime keyword on the init function itself:

```zig
pub fn main() void {
    const itab = comptime initItab(Impl);
    itab.bar();
}

```

So… maybe you can actually get both constraints satisfied at once here? Odd. I think someone should look a little deeper into the discrepancy here.

---

<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:** [July 25, 2024, 3:07am UTC](https://ziggit.dev/t/programmatically-creating-an-interface-table-for-a-set-of-implementation-fxns/5342/6 "2024-07-25T03:07:56Z")

</div>

no problem with separating reification from initialization… my objective is to minimize the about of information required by my “newbie” users to specify an interface… the more i create artificats like a vtable inside my framework, the better…

what is **VERY** important is the generated vtable is usable as runtime; to that end, having @sizeOf yield an non-zero answer was my test…

in my use-case, these generate vtables are used in my framework’s “upstream meta-program” – where efficiency is much less of an issue… if the compiler can figure out that this `inline` initialized table in fact is constant, that’s upside… as a practical matter, there is no “monkey-patching” happening at runtime; i’m simply call implementation functions through an interface object…

---

<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:** [July 25, 2024, 3:13am UTC](https://ziggit.dev/t/programmatically-creating-an-interface-table-for-a-set-of-implementation-fxns/5342/7 "2024-07-25T03:13:11Z")

</div>

Yeah, with that last method, I’m getting a reported size of `16` bytes when marked with and without `comptime`. That’s true for debug and release-fast. It looks like that indirection may do the trick then. I’d still like to know more about the discrepancy with reification here. Either way, hope that helps.

---

<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:** [July 25, 2024, 4:18pm UTC](https://ziggit.dev/t/programmatically-creating-an-interface-table-for-a-set-of-implementation-fxns/5342/8 "2024-07-25T16:18:20Z")

</div>

I suddenly realized what the issue here is while chewing on some dried squid: you’re missing one level of indirection. `default_value` needs to be a pointer to a function pointer:

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

const print = std.log.debug;

const Impl = struct {
    pub fn foo(x: u32) void {
        print("foo({d})", .{x});
    }
    pub fn bar() void {
        print("bar", .{});
    }
};

fn ItabType(T: type) type {
    comptime {
        const TI = @typeInfo(T);

        const decls = TI.Struct.decls;

        var fld_list: [decls.len]std.builtin.Type.StructField = undefined;

        for (decls, 0..) |decl, i| {
            const func = @field(T, decl.name);
            const func_ptr = &func;

            fld_list[i] = std.builtin.Type.StructField{
                .name = decl.name,
                .type = *const @TypeOf(func),
                .default_value = @ptrCast(&func_ptr),
                .is_comptime = false,
                .alignment = 0,
            };
        }

        const freeze = fld_list;

        return @Type(.{ .Struct = .{
            .layout = .auto,
            .fields = freeze[0..],
            .decls = &.{},
            .is_tuple = false,
            .backing_integer = null,
        } });
    }
}

pub fn main() void {
    const itab: ItabType(Impl) = .{};
    itab.bar();
}

```

🦑🦑🦑

---

<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:** [July 25, 2024, 4:47pm UTC](https://ziggit.dev/t/programmatically-creating-an-interface-table-for-a-set-of-implementation-fxns/5342/9 "2024-07-25T16:47:47Z")

</div>

Aha, sneaky!
