Questions related to working with Tuples?

Hey Folks,

Thanks to everyone who has been so helpful as I continue getting up to speed with Zig.

It has admittedly been a little more of a slog than I hoped, but the progress is starting to feel tangible.

I’m currently exploring what it would feel like to build a higher level DSL-ish thing in Zig.

I recognize that this is probably a little bit outside the expected design space of the language, there are some promising bits here, if I could just understand why they’re not working and/or what I need to do to make them work.

Here’s a gist that outlines the problem space, with the content pasted below:

const std = @import("std");

const print = std.debug.print;

// The dreaded, "unable to evaluate constant expression"
//
// I'm having a difficult time understanding when the zig compiler transitions
// my code execution from comptime to runtime and I'm pretty sure this is the
// root cause of my struggles here.
//
// I do understand that I may be looking for more dynamism than Zig is
// prepared to provide.
//
// For clarity, I'm actually attempting to construct large and wide trees of
// homogeneous entities that compose heterogeneous collections of attributes
// without allocating massive blocks of memory for every single potential
// attribute.
//
// Is something like the following even possible in Zig?
//
// const elem = div(.{
//     name("abcd"),
//     width(800),
//     height(600),
//     children(.{
//          div(.{ name("efgh") }),
//          div(.{ name("ijkl") }),
//          div(.{ name("mnop") }),
//     }),
// });
//
// There are a collection of questions below, and any code that doesn't compile
// in zig version 0.8.0 has been commented out.
//
// Ideally, this code could be uncommented, repaired and compiled such that the
// the commented out test will pass.
//
// Any tips appreciated.

const FakeParamName = enum {
    Aye,
    Bee,
    Cee,
};

fn FakeParam(comptime T: type) type {
    return struct {
        name: FakeParamName,
        value: T,
    };
}

const FakeUintParam = FakeParam(u32);
const FakeStringParam = FakeParam([]const u8);
const FakeBoolParam = FakeParam(bool);

pub fn Aye(value: u32) FakeUintParam {
    return .{ .name = FakeParamName.Aye, .value = value };
}

pub fn Bee(value: []const u8) FakeStringParam {
    return .{ .name = FakeParamName.Bee, .value = value };
}

pub fn Cee(value: bool) FakeBoolParam {
    return .{ .name = FakeParamName.Cee, .value = value };
}

// QUESTION: How does one set the type of a tuple?
// const stored_params: FakeParam(type) = undefined;

// I'd like to store the values sent to this function
// QUESTION: How does one store an anytype?
fn storeParams(params: anytype) void {
    print("params: {any}\n", .{params});
    // This isn't it:
    // stored_params = params;

    var i: usize = 0;
    while (i < params.len) {
        // QUESTION: Why doesn't this work?
        // const name = params[i].name;
        // QUESTION: Why doesn't this work?
        // print("param found: {any}\n", .{params[i].name});
        i += 1;
    }
}

// Return the .value for the first param whose name matches the provided name.
// Q3: How does one get a value of an unknown type?
// fn getParamByName(name: FakeParamName) ?anytype {
//     var i: usize = 0;
//     while (i < stored_params.len) {
//         if (stored_params[i].name == name) {
//             return stored_params[i].value;
//         }
//     }
//
//     return null;
// }

test "How to store and load tuple values?" {
    storeParams(.{
        Aye(42),
        Bee("bee"),
        Cee(false),
    });

    // const aye = getParamByName(FakeParamName.Aye);
    // try expectEqual(aye, 42);
    // const bee = getParamByName(FakeParamName.Bee);
    // try expectEqualStrings(bee, "bee");
    // const cee = getParamByName(FakeParamName.Cee);
    // try expectEqual(cee, false);
}

You want inline while for it to work at runtime.

Maybe I’m also doing something wrong in the definitions?

When I add the “inline” keyword in front of the while loop, I get this error:

./tuples.zig:81:21: error: unable to evaluate constant expression
    inline while (i < params.len) {
                    ^
./tuples.zig:104:16: note: called from here
    storeParams(.{
               ^
./tuples.zig:103:44: note: called from here
test "How to store and load tuple values?" {
                                           ^
./tuples.zig:104:16: note: referenced here
    storeParams(.{
               ^

You also need to change var i: usize = 0 to comptime var i = 0 since the unrolling makes i comptime known and tuple access requires comptime index.