Generating types at runtime

I have been trying to create a simple function to generate type at runtime, here’s the following code:

const std = @import("std");

const Type = std.builtin.Type;

const print = std.debug.print;

const anonymous_struct = struct { []const u8, u8, u8 };

fn create_tuple(allocator: std.mem.Allocator, input: []u8) !type {
    var fields = std.ArrayList(Type.StructField).init(allocator);
    defer fields.deinit();

    var index: u8 = '0';

    var i: usize = 0;

    for (input) |field| {
        try fields.append(.{
            .name = &[_:0]u8{index},
            .type = @TypeOf(field),
            .default_value = @as(*const anyopaque, @ptrCast(&(field + 1))),
            .is_comptime = false,
            .alignment = @alignOf(@TypeOf(field)),
        });

        i += 1;
        index += 1;
    }

    return @Type(.{
        .Struct = Type.Struct{
            .is_tuple = true,
            .decls = &[_]Type.Declaration{},
            .backing_integer = null,
            .fields = try fields.toOwnedSlice(),
            .layout = .auto,
        },
    });
}

pub fn main() !void {
    const input = [_]u8{ 'a', 'b', 'c' };

    const slice = input[0..];

    const allocator = std.heap.page_allocator;

    const tuple_type = try create_tuple(allocator, @constCast(slice));

    const tuple = tuple_type{};

    print("{any}: {any}\n", .{ slice, tuple });
}

I am getting the following error:

run
└─ run zig_project_02
   └─ zig build-exe zig_project_02 Debug native 1 errors
C:\zig\lib\std\os\windows.zig:1745:33: error: comptime call of extern function
    return kernel32.VirtualAlloc(addr, size, alloc_type, flProtect) orelse {
           ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\zig\lib\std\heap\PageAllocator.zig:24:42: note: called from here
        const addr = windows.VirtualAlloc(       
                     ~~~~~~~~~~~~~~~~~~~~^       
C:\zig\lib\std\mem\Allocator.zig:86:29: note: called from here
    return self.vtable.alloc(self.ptr, len, ptr_align, ret_addr);
           ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\zig\lib\std\mem\Allocator.zig:225:35: note: called from here
    const byte_ptr = self.rawAlloc(byte_count, log2a(alignment), return_address) orelse return Error.OutOfMemory;
                     ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\zig\lib\std\mem\Allocator.zig:211:40: note: called from here
    return self.allocBytesWithAlignment(alignment, byte_count, return_address);
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\zig\lib\std\mem\Allocator.zig:205:75: note: called from here
    const ptr: [*]align(a) T = @ptrCast(try self.allocWithSizeAndAlignment(@sizeOf(T), a, n, return_address));
                                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\zig\lib\std\mem\Allocator.zig:193:41: note: called from here
    return self.allocAdvancedWithRetAddr(T, alignment, n, @returnAddress());
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\zig\lib\std\array_list.zig:457:67: note: called from here
                const new_memory = try self.allocator.alignedAlloc(T, alignment, new_capacity);   
                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~    
C:\zig\lib\std\array_list.zig:434:51: note: called from here
            return self.ensureTotalCapacityPrecise(better_capacity~
src\main.zig:18:26: note: called from here
        try fields.append(.{
            ~~~~~~~~~~~~~^
src\main.zig:48:40: note: called from here
    const tuple_type = try create_tuple(allocator, @constCast(slice));
                           ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
referenced by:
    callMain: C:\zig\lib\std\start.zig:524:32
    WinStartup: C:\zig\lib\std\start.zig:363:45
    remaining reference traces hidden; use '-freference-trace' to see all reference traces
error: the following command failed with 1 compilation errors:    
C:\zig\zig.exe build-exe -ODebug -Mroot=C:\Learning\Zig\reflections\src\main.zig --cache-dir C:\Learning\Zig\reflections\.zig-cache --global-cache-dir C:\Users\legend\AppData\Local\zig --name zig_project_02 -flto --listen=-
Build Summary: 0/5 steps succeeded; 1 failed (disable with --summary none)
run transitive failure
└─ run reflections transitive failure
   ├─ zig build-exe reflections Debug native 1 errors
   └─ install transitive failure
      └─ install reflections transitive failure
         └─ zig build-exe reflections Debug native (reused)    
error: the following build command failed with exit code 1:       
C:\Learning\Zig\reflections\.zig-cache\o\97c05016496160a42f4b765de720eb37\build.exe C:\zig\zig.exe C:\Learning\Zig\reflections C:\Learning\Zig\revlections\.zig-cache C:\Users\legend\AppData\Local\zig --seed 0xf7c7b2b7 -Z7276550ef218267c run

And how do I cleanup the arraylist memory?

You can’t generate types at runtime in Zig.

The fact that your function returns type makes it a comptime-only function, which is why you’re getting an error when accessing a heap allocator at comptime.

If you want to do something of this sort, you will have to generate your own runtime abstractions where your “types” are represented as data.

1 Like

Is there any chance of zig getting runtime reflections in the future?

Most probably not.

What is your reason for wanting runtime?
Comptime has way more support.

If you describe what you actually want to do, maybe it could be achieved in a different way.

The function create_tuple for example could be made runtime by not doing @Type and just returning the Type struct, which can totally be used at runtime.

So, I was working on creating a serializer for json string. Since there is no strict typing, arrays/lists in json have dynamic type and length, so was trying to generate a type based on the parsed array/list in json string into a tuple type so that I can access it like:

_ = field[0];
_ = field[1];

Note, my intention was only for indexing the array/list in json.

use a tagged union, this is essential what runtime types are anyway, its also how std.json handles that problem

4 Likes