Newbie questions about zig-clap and other projects

i have read this project line: 875: zig-clap/clap.zig at master · Hejsil/zig-clap · GitHub


fn Positionals(
    comptime Id: type,
    comptime params: []const Param(Id),
    comptime value_parsers: anytype,
    comptime multi_arg_kind: MultiArgKind,
) type {
    var fields_len: usize = 0;
    for (params) |param| {
        const longest = param.names.longest();
        if (longest.kind != .positional)
            continue;
        fields_len += 1;
    }

    var fields: [fields_len]std.builtin.Type.StructField = undefined;
    var i: usize = 0;
    for (params) |param| {
        const longest = param.names.longest();
        if (longest.kind != .positional)
            continue;

        const T = ParamType(Id, param, value_parsers);
        const FieldT = switch (param.takes_value) {
            .none => continue,
            .one => ?T,
            .many => switch (multi_arg_kind) {
                .slice => []const T,
                .list => std.ArrayListUnmanaged(T),
            },
        };

        fields[i] = .{
            .name = std.fmt.comptimePrint("{}", .{i}),
            .type = FieldT,
            .default_value_ptr = null,
            .is_comptime = false,
            .alignment = @alignOf(FieldT),
        };
        i += 1;
    }

    return @Type(.{ .@"struct" = .{
        .layout = .auto,
        .fields = &fields,
        .decls = &.{},
        .is_tuple = true,
    } });
}

I have 3 question
1)

var fields: [fields_len]std.builtin.Type.StructField = undefined; 

created on function stack but its address use in return

return @Type(.{ .@"struct" = .{
        .layout = .auto,
        .fields = &fields,
        .decls = &.{},
        .is_tuple = true,
    } });

this have to be memory corruption but it works magically

  1. how this return @Type returns something like slice or array on runtime? it looks paranormal :expressionless:

  2. i read a lot of source code on tigerbeetle and bun project. I have seen a lot of magic like these too. How can i deeply understand this concepts. one day something looks impossible but another day someone make it :smiley:

For example, as i can read I cant write ‘add’ or ‘minus’ operator overloading like c++, python or others languages magic methods but @Vector can do this :smiley:, maybe there is an hack for this maybe i can write builtin methods, I only need to know how can tiggerbeetle or bun coders know these? Where is the holly source?

Types are comptime-only. Nothing you saw there was happening at runtime.
Comptime Zig is a managed memory language, you can return pointers to stack and zig will make it work.

9 Likes

Also, even if @Type wasn’t a builtin function, that code isn’t necessarily returning a pointer to stack-allocated memory. It’s passing the address of the array into the function, but the function doesn’t have to return a value containing that address. For a contrived example:

const std = @import("std");
fn writeQoiHeader(writer: std.io.AnyWriter, size_x: u32, size_y: u32, channels: u8, linear: bool) anyerror!void {
    var header: [14]u8 = undefined;
    header[0x0..0x4].* = "qoif".*;
    std.mem.writeInt(u32, header[0x4..0x8], size_x, .big);
    std.mem.writeInt(u32, header[0x8..0xC], size_y, .big);
    header[0xC] = channels;
    header[0xD] = @intFromBool(linear);
    return writer.writeAll(&header);
}

This function returns the result of writer.writeAll(&header), but that doesn’t mean we’re returning the address of header. The return value is of type anyerror!void, which doesn’t include any addresses.

In general, you can’t determine if a function is returning a dangling pointer just by analyzing the syntax of the function.

(Sorry if I’m being too pedantic!)

3 Likes

Not pedantic at all that’s a solid clarification. You’re right, return type matters way more than just what’s passed around internally. Appreciate it!

3 Likes