Open ikskuh opened 3 years ago
This builtin allows to create nicer comptime code which replaces some generic public functions.
Could you perhaps give an example of this (i.e. functions that currently exist in the std lib/elsewhere that could use @unrollArgumentTuple
)?
I'm struggling to see why your example wouldn't just be written as
fn allocateWithLog(logger: Logger, allocator: *std.mem.Allocator, len: usize) ![]u8
See this example:
Usage:`` https://gist.github.com/MasterQ32/ef7187c56dcc195855390b234226d516#file-closure-zig-L22-L26
Implementation: https://gist.github.com/MasterQ32/ef7187c56dcc195855390b234226d516#file-closure-zig-L67-L69
With this proposal, you can just call _ = closed.invoke(1);
instead of _ = closed.invoke(.{1});
This is just a small example though, there are better use cases, but it's a good one already :)
I'm struggling to see why your example wouldn't just be written as...
Yeah, this example was very artifical, just to be short. A real-world example would be some heavy comptime computation stuff being longer than the whole proposal itself
Add new builtin: @unrollArgumentTuple
Semantics
This builtin accepts any
function
that has the following requirements met:@typeInfo(function) == .Fn
.is_tuple = true
comptime
The builtin returns a new function that:
function
except for the last one@TypeOf(tuple)
and passes the created tuple tofunction
function
is returned verbatimUsage Example
Implementation Example
will be unrolled into
Use Case
This builtin allows to create nicer comptime code which replaces some generic public functions.
Before:
foo(.{ a, b, c})
After:foo(a, b, c)
Tuples were introduced primarily to create a replacement for variadic arguments but are now also used a lot in
comptime
code to create computable argument lists. This proposal allows to properly instantiate those computed APIs with actual argument list and reduces the amount of confusing error messages and error stack length when a wrong argument is passed to such a function.Alternative
This behaviour is currently semi-ish implementable in user space by repeating a lot of code:
Extend to see implementation
```zig fn createCallWrapper(comptime FunctionType: type, comptime function: anytype) FunctionType { const fn_info = @typeInfo(FunctionType).Fn; const fn_args = fn_info.args; const R = fn_info.return_type orelse @compileError("Function must be non-generic"); comptime var A: [fn_args.len]type = undefined; inline for(A) |*t,i| { t.* = fn_args[i].arg_type orelse @compileError("Function must be non-generic"); } const Wrappers = struct { fn fn1(a0: A[0]) R { return function(a0,.{}); } fn fn2(a0: A[0], a1:A[1]) R { return function(a0,.{a1}); } fn fn3(a0: A[0], a1:A[1], a2:A[2]) R { return function(a0,.{a1,a2}); } fn fn4(a0: A[0], a1:A[1], a2:A[2], a3:A[3]) R { return function(a0,.{a1,a2,a3}); } fn fn5(a0: A[0], a1:A[1], a2:A[2], a3:A[3], a4:A[4]) R { return function(a0,.{a1,a2,a3,a4}); } fn fn6(a0: A[0], a1:A[1], a2:A[2], a3:A[3], a4:A[4], a5:A[5]) R { return function(a0,.{a1,a2,a3,a4,a5}); } fn fn7(a0: A[0], a1:A[1], a2:A[2], a3:A[3], a4:A[4], a5:A[5], a6:A[6]) R { return function(a0,.{a1,a2,a3,a4,a5,a6}); } fn fn8(a0: A[0], a1:A[1], a2:A[2], a3:A[3], a4:A[4], a5:A[5], a6:A[6], a7:A[7]) R { return function(a0,.{a1,a2,a3,a4,a5,a6,a7}); } fn fn9(a0: A[0], a1:A[1], a2:A[2], a3:A[3], a4:A[4], a5:A[5], a6:A[6], a7:A[7], a8:A[8]) R { return function(a0,.{a1,a2,a3,a4,a5,a6,a7,a8}); } fn fn10(a0: A[0], a1:A[1], a2:A[2], a3:A[3], a4:A[4], a5:A[5], a6:A[6], a7:A[7], a8:A[8], a9:A[9]) R { return function(a0,.{a1,a2,a3,a4,a5,a6,a7,a8,a9}); } fn fn11(a0: A[0], a1:A[1], a2:A[2], a3:A[3], a4:A[4], a5:A[5], a6:A[6], a7:A[7], a8:A[8], a9:A[9], a10:A[10]) R { return function(a0,.{a1,a2,a3,a4,a5,a6,a7,a8,a9,a10}); } fn fn12(a0: A[0], a1:A[1], a2:A[2], a3:A[3], a4:A[4], a5:A[5], a6:A[6], a7:A[7], a8:A[8], a9:A[9], a10:A[10], a11:A[11]) R { return function(a0,.{a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11}); } fn fn13(a0: A[0], a1:A[1], a2:A[2], a3:A[3], a4:A[4], a5:A[5], a6:A[6], a7:A[7], a8:A[8], a9:A[9], a10:A[10], a11:A[11], a12:A[12]) R { return function(a0,.{a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12}); } fn fn14(a0: A[0], a1:A[1], a2:A[2], a3:A[3], a4:A[4], a5:A[5], a6:A[6], a7:A[7], a8:A[8], a9:A[9], a10:A[10], a11:A[11], a12:A[12], a13:A[13]) R { return function(a0,.{a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13}); } fn fn15(a0: A[0], a1:A[1], a2:A[2], a3:A[3], a4:A[4], a5:A[5], a6:A[6], a7:A[7], a8:A[8], a9:A[9], a10:A[10], a11:A[11], a12:A[12], a13:A[13], a14:A[14]) R { return function(a0,.{a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14}); } fn fn16(a0: A[0], a1:A[1], a2:A[2], a3:A[3], a4:A[4], a5:A[5], a6:A[6], a7:A[7], a8:A[8], a9:A[9], a10:A[10], a11:A[11], a12:A[12], a13:A[13], a14:A[14], a15:A[15]) R { return function(a0,.{a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15}); } }; return switch(fn_args.len) { 1 => Wrappers.fn1, 2 => Wrappers.fn2, 3 => Wrappers.fn3, 4 => Wrappers.fn4, 5 => Wrappers.fn5, 6 => Wrappers.fn6, 7 => Wrappers.fn7, 8 => Wrappers.fn8, 9 => Wrappers.fn9, 10 => Wrappers.fn10, 11 => Wrappers.fn11, 12 => Wrappers.fn12, 13 => Wrappers.fn13, 14 => Wrappers.fn14, 15 => Wrappers.fn15, 16 => Wrappers.fn16, else => @compileError("Unsupported number of arguments!"), }; } ```