authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-07 17:52:24-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-08 19:15:10+02:00
log8dfddf95fee5982d22512c0ac15278eabac5bcbb
tree0cd22c5bea3cb861971dc4820e59d8b41120e698
parent3239f672d2aa61ad0fea0f400cd7917fa354ea0f

std.meta: deprecate fieldInfo, fieldNames, fieldTypes

Technically there is one valid use case for `fieldNames` which is use with an enum or union so that those types can be used interchangeably. But in practice these functions are mainly abused, because the callsites always know what kind of type it is. This commit encourages Zig users to embrace using `@typeInfo` directly when doing type reflection.

15 files changed, 41 insertions(+), 29 deletions(-)

lib/std/Build.zig+2-2
...@@ -1109,7 +1109,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw...@@ -1109,7 +1109,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
1109 const type_id = comptime typeToEnum(T);1109 const type_id = comptime typeToEnum(T);
1110 const enum_options = if (type_id == .@"enum" or type_id == .enum_list) blk: {1110 const enum_options = if (type_id == .@"enum" or type_id == .enum_list) blk: {
1111 const EnumType = if (type_id == .enum_list) @typeInfo(T).pointer.child else T;1111 const EnumType = if (type_id == .enum_list) @typeInfo(T).pointer.child else T;
1112 const field_names = comptime std.meta.fieldNames(EnumType);1112 const field_names = @typeInfo(EnumType).@"enum".field_names;
1113 var options = std.array_list.Managed([]const u8).initCapacity(b.allocator, field_names.len) catch @panic("OOM");1113 var options = std.array_list.Managed([]const u8).initCapacity(b.allocator, field_names.len) catch @panic("OOM");
11141114
1115 inline for (field_names) |field_name| {1115 inline for (field_names) |field_name| {
...@@ -1420,7 +1420,7 @@ pub fn parseTargetQuery(options: std.Target.Query.ParseOptions) error{ParseFaile...@@ -1420,7 +1420,7 @@ pub fn parseTargetQuery(options: std.Target.Query.ParseOptions) error{ParseFaile
1420 \\available operating systems:1420 \\available operating systems:
1421 \\1421 \\
1422 , .{diags.os_name.?});1422 , .{diags.os_name.?});
1423 inline for (comptime std.meta.fieldNames(Target.Os.Tag)) |field_name| {1423 inline for (@typeInfo(Target.Os.Tag).@"enum".field_names) |field_name| {
1424 std.debug.print(" {s}\n", .{field_name});1424 std.debug.print(" {s}\n", .{field_name});
1425 }1425 }
1426 return error.ParseFailed;1426 return error.ParseFailed;
lib/std/enums.zig+3-2
...@@ -33,7 +33,8 @@ pub fn fromInt(comptime E: type, integer: anytype) ?E {...@@ -33,7 +33,8 @@ pub fn fromInt(comptime E: type, integer: anytype) ?E {
33pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type {33pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type {
34 @setEvalBranchQuota(@typeInfo(E).@"enum".field_names.len + eval_branch_quota_cushion);34 @setEvalBranchQuota(@typeInfo(E).@"enum".field_names.len + eval_branch_quota_cushion);
35 const default_ptr: ?*const anyopaque = if (field_default) |d| @ptrCast(&d) else null;35 const default_ptr: ?*const anyopaque = if (field_default) |d| @ptrCast(&d) else null;
36 return @Struct(.auto, null, std.meta.fieldNames(E), &@splat(Data), &@splat(.{ .default_value_ptr = default_ptr }));36 const field_names = @typeInfo(E).@"enum".field_names;
37 return @Struct(.auto, null, field_names, &@splat(Data), &@splat(.{ .default_value_ptr = default_ptr }));
37}38}
3839
39/// Looks up the supplied field values in the given enum type.40/// Looks up the supplied field values in the given enum type.
...@@ -454,7 +455,7 @@ pub fn EnumMap(comptime E: type, comptime V: type) type {...@@ -454,7 +455,7 @@ pub fn EnumMap(comptime E: type, comptime V: type) type {
454 }455 }
455 }456 }
456 } else {457 } else {
457 inline for (std.meta.fieldNames(E)) |field_name| {458 inline for (@typeInfo(E).@"enum".field_names) |field_name| {
458 const key = @field(E, field_name);459 const key = @field(E, field_name);
459 if (@field(init_values, field_name)) |*v| {460 if (@field(init_values, field_name)) |*v| {
460 const i = comptime Indexer.indexOf(key);461 const i = comptime Indexer.indexOf(key);
lib/std/meta.zig+18-7
...@@ -197,15 +197,17 @@ test containerLayout {...@@ -197,15 +197,17 @@ test containerLayout {
197 try testing.expect(containerLayout(U3) == .@"extern");197 try testing.expect(containerLayout(U3) == .@"extern");
198}198}
199199
200/// Instead of this function, prefer to use e.g. `@typeInfo(foo).@"struct".decl_names`200/// Returns the list of declaration names of namespace types.
201/// directly when you know what kind of type it is.201///
202/// This function is only useful when the callsite does not know statically
203/// which kind of container it is.
202pub fn declarations(comptime T: type) []const [:0]const u8 {204pub fn declarations(comptime T: type) []const [:0]const u8 {
203 return switch (@typeInfo(T)) {205 return switch (@typeInfo(T)) {
204 .@"struct" => |info| info.decl_names,206 .@"struct" => |info| info.decl_names,
205 .@"enum" => |info| info.decl_names,207 .@"enum" => |info| info.decl_names,
206 .@"union" => |info| info.decl_names,208 .@"union" => |info| info.decl_names,
207 .@"opaque" => |info| info.decl_names,209 .@"opaque" => |info| info.decl_names,
208 else => @compileError("Expected struct, enum, union, or opaque type, found '" ++ @typeName(T) ++ "'"),210 else => comptime unreachable, // type lacks namespace
209 };211 };
210}212}
211213
...@@ -241,10 +243,13 @@ test declarations {...@@ -241,10 +243,13 @@ test declarations {
241}243}
242244
243/// To be removed after Zig 0.17.0 is tagged.245/// To be removed after Zig 0.17.0 is tagged.
244pub const declarationInfo = @compileError("Deprecated; use '@hasDecl' instead");246pub const declarationInfo = @compileError("deprecated in favor of @hasDecl");
245/// To be removed after Zig 0.17.0 is tagged.247/// To be removed after Zig 0.17.0 is tagged.
246pub const fields = @compileError("Deprecated; use 'fieldNames' and 'fieldTypes' instead");248pub const fields = @compileError("deprecated in favor of @typeInfo");
247249
250/// Deprecated in favor of `@typeInfo`.
251///
252/// To be removed after 0.17.0 is tagged.
248pub fn fieldInfo(comptime T: type, comptime field: FieldEnum(T)) switch (@typeInfo(T)) {253pub fn fieldInfo(comptime T: type, comptime field: FieldEnum(T)) switch (@typeInfo(T)) {
249 .@"struct" => struct { name: [:0]const u8, type: type, attrs: Type.Struct.FieldAttributes },254 .@"struct" => struct { name: [:0]const u8, type: type, attrs: Type.Struct.FieldAttributes },
250 .@"union" => struct { name: [:0]const u8, type: type, attrs: Type.Union.FieldAttributes },255 .@"union" => struct { name: [:0]const u8, type: type, attrs: Type.Union.FieldAttributes },
...@@ -298,13 +303,16 @@ test fieldInfo {...@@ -298,13 +303,16 @@ test fieldInfo {
298 try testing.expect(comptime uf.type == u8);303 try testing.expect(comptime uf.type == u8);
299}304}
300305
306/// Deprecated in favor of `@typeInfo`.
307///
308/// To be removed after 0.17.0 is tagged.
301pub fn fieldNames(comptime T: type) []const [:0]const u8 {309pub fn fieldNames(comptime T: type) []const [:0]const u8 {
302 return switch (@typeInfo(T)) {310 return switch (@typeInfo(T)) {
303 .@"struct" => |s| s.field_names,311 .@"struct" => |s| s.field_names,
304 .@"union" => |u| u.field_names,312 .@"union" => |u| u.field_names,
305 .@"enum" => |e| e.field_names,313 .@"enum" => |e| e.field_names,
306 .error_set => |es| es.error_names.?,314 .error_set => |es| es.error_names.?,
307 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),315 else => comptime unreachable,
308 };316 };
309}317}
310318
...@@ -336,11 +344,14 @@ test fieldNames {...@@ -336,11 +344,14 @@ test fieldNames {
336 try testing.expectEqualSlices(u8, u1names[1], "b");344 try testing.expectEqualSlices(u8, u1names[1], "b");
337}345}
338346
347/// Deprecated in favor of `@typeInfo`.
348///
349/// To be removed after 0.17.0 is tagged.
339pub fn fieldTypes(comptime T: type) []const type {350pub fn fieldTypes(comptime T: type) []const type {
340 return switch (@typeInfo(T)) {351 return switch (@typeInfo(T)) {
341 .@"struct" => |s| s.field_types,352 .@"struct" => |s| s.field_types,
342 .@"union" => |u| u.field_types,353 .@"union" => |u| u.field_types,
343 else => @compileError("Expected struct or union type, found '" ++ @typeName(T) ++ "'"),354 else => comptime unreachable,
344 };355 };
345}356}
346357
lib/std/zig/AstGen.zig+2-2
...@@ -74,13 +74,13 @@ src_hasher: std.zig.SrcHasher,...@@ -74,13 +74,13 @@ src_hasher: std.zig.SrcHasher,
74const InnerError = error{ OutOfMemory, AnalysisFail };74const InnerError = error{ OutOfMemory, AnalysisFail };
7575
76fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 {76fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 {
77 const field_count = std.meta.fieldNames(@TypeOf(extra)).len;77 const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len;
78 try astgen.extra.ensureUnusedCapacity(astgen.gpa, field_count);78 try astgen.extra.ensureUnusedCapacity(astgen.gpa, field_count);
79 return addExtraAssumeCapacity(astgen, extra);79 return addExtraAssumeCapacity(astgen, extra);
80}80}
8181
82fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 {82fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 {
83 const field_count = std.meta.fieldNames(@TypeOf(extra)).len;83 const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len;
84 const extra_index: u32 = @intCast(astgen.extra.items.len);84 const extra_index: u32 = @intCast(astgen.extra.items.len);
85 astgen.extra.items.len += field_count;85 astgen.extra.items.len += field_count;
86 setExtra(astgen, extra_index, extra);86 setExtra(astgen, extra_index, extra);
lib/std/zig/LibCInstallation.zig+1-1
...@@ -43,7 +43,7 @@ pub const FindError = error{...@@ -43,7 +43,7 @@ pub const FindError = error{
43pub fn parse(allocator: Allocator, io: Io, libc_file: []const u8, target: *const std.Target) !LibCInstallation {43pub fn parse(allocator: Allocator, io: Io, libc_file: []const u8, target: *const std.Target) !LibCInstallation {
44 var self: LibCInstallation = .{};44 var self: LibCInstallation = .{};
4545
46 const field_names = comptime std.meta.fieldNames(LibCInstallation);46 const field_names = @typeInfo(LibCInstallation).@"struct".field_names;
47 const FoundKey = struct {47 const FoundKey = struct {
48 found: bool,48 found: bool,
49 allocated: ?[]u8,49 allocated: ?[]u8,
lib/std/zig/llvm/Builder.zig+2-2
...@@ -9517,7 +9517,7 @@ pub const Metadata = packed struct(u32) {...@@ -9517,7 +9517,7 @@ pub const Metadata = packed struct(u32) {
9517 nodes: anytype,9517 nodes: anytype,
9518 w: *Writer,9518 w: *Writer,
9519 ) !void {9519 ) !void {
9520 const names = comptime std.meta.fieldNames(@TypeOf(nodes));9520 const names = @typeInfo(@TypeOf(nodes)).@"struct".field_names;
95219521
9522 comptime var fmt_str: []const u8 = "{[distinct]s}{[node]s}(";9522 comptime var fmt_str: []const u8 = "{[distinct]s}{[node]s}(";
9523 inline for (names) |name| fmt_str = fmt_str ++ "{[" ++ name ++ "]f}";9523 inline for (names) |name| fmt_str = fmt_str ++ "{[" ++ name ++ "]f}";
...@@ -13484,7 +13484,7 @@ fn metadataSimpleAssumeCapacity(self: *Builder, tag: Metadata.Tag, value: anytyp...@@ -13484,7 +13484,7 @@ fn metadataSimpleAssumeCapacity(self: *Builder, tag: Metadata.Tag, value: anytyp
13484 builder: *const Builder,13484 builder: *const Builder,
13485 pub fn hash(_: @This(), key: Key) u32 {13485 pub fn hash(_: @This(), key: Key) u32 {
13486 var hasher = std.hash.Wyhash.init(std.hash.int(@backingInt(key.tag)));13486 var hasher = std.hash.Wyhash.init(std.hash.int(@backingInt(key.tag)));
13487 inline for (comptime std.meta.fieldNames(@TypeOf(value))) |field_name| {13487 inline for (@typeInfo(@TypeOf(value)).@"struct".field_names) |field_name| {
13488 hasher.update(std.mem.asBytes(&@field(key.value, field_name)));13488 hasher.update(std.mem.asBytes(&@field(key.value, field_name)));
13489 }13489 }
13490 return @truncate(hasher.final());13490 return @truncate(hasher.final());
lib/std/zig/llvm/bitcode_writer.zig+1-1
...@@ -246,7 +246,7 @@ pub fn BitcodeWriter(comptime types: []const type) type {...@@ -246,7 +246,7 @@ pub fn BitcodeWriter(comptime types: []const type) type {
246246
247 try self.bitcode.writeBits(comptime abbrevId(Abbrev), abbrev_len);247 try self.bitcode.writeBits(comptime abbrevId(Abbrev), abbrev_len);
248248
249 const field_names = comptime std.meta.fieldNames(Abbrev);249 const field_names = @typeInfo(Abbrev).@"struct".field_names;
250250
251 // This abbreviation might only contain literals251 // This abbreviation might only contain literals
252 if (field_names.len == 0) return;252 if (field_names.len == 0) return;
lib/std/zig/system.zig+1-1
...@@ -973,7 +973,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ...@@ -973,7 +973,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
973 // relying on `builtin.target`.973 // relying on `builtin.target`.
974 const all_abis = comptime blk: {974 const all_abis = comptime blk: {
975 assert(@backingInt(Target.Abi.none) == 0);975 assert(@backingInt(Target.Abi.none) == 0);
976 const field_names = std.meta.fieldNames(Target.Abi)[1..];976 const field_names = @typeInfo(Target.Abi).@"enum".field_names[1..];
977 var array: [field_names.len]Target.Abi = undefined;977 var array: [field_names.len]Target.Abi = undefined;
978 for (field_names, 0..) |field_name, i| {978 for (field_names, 0..) |field_name, i| {
979 array[i] = @field(Target.Abi, field_name);979 array[i] = @field(Target.Abi, field_name);
src/Air/Liveness.zig+3-3
...@@ -351,7 +351,7 @@ const Analysis = struct {...@@ -351,7 +351,7 @@ const Analysis = struct {
351 extra: std.ArrayList(u32),351 extra: std.ArrayList(u32),
352352
353 fn addExtra(a: *Analysis, extra: anytype) Allocator.Error!u32 {353 fn addExtra(a: *Analysis, extra: anytype) Allocator.Error!u32 {
354 const field_count = std.meta.fieldNames(@TypeOf(extra)).len;354 const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len;
355 try a.extra.ensureUnusedCapacity(a.gpa, field_count);355 try a.extra.ensureUnusedCapacity(a.gpa, field_count);
356 return addExtraAssumeCapacity(a, extra);356 return addExtraAssumeCapacity(a, extra);
357 }357 }
...@@ -1012,7 +1012,7 @@ fn analyzeInstBlock(...@@ -1012,7 +1012,7 @@ fn analyzeInstBlock(
1012 const block_scope = data.block_scopes.get(inst).?;1012 const block_scope = data.block_scopes.get(inst).?;
1013 const num_deaths = data.live_set.count() - block_scope.live_set.count();1013 const num_deaths = data.live_set.count() - block_scope.live_set.count();
10141014
1015 try a.extra.ensureUnusedCapacity(gpa, num_deaths + std.meta.fieldNames(Block).len);1015 try a.extra.ensureUnusedCapacity(gpa, num_deaths + @typeInfo(Block).@"struct".field_names.len);
1016 const extra_index = a.addExtraAssumeCapacity(Block{1016 const extra_index = a.addExtraAssumeCapacity(Block{
1017 .death_count = num_deaths,1017 .death_count = num_deaths,
1018 });1018 });
...@@ -1275,7 +1275,7 @@ fn analyzeInstCondBr(...@@ -1275,7 +1275,7 @@ fn analyzeInstCondBr(
1275 // Write the mirrored deaths to `extra`1275 // Write the mirrored deaths to `extra`
1276 const then_death_count = @as(u32, @intCast(then_mirrored_deaths.items.len));1276 const then_death_count = @as(u32, @intCast(then_mirrored_deaths.items.len));
1277 const else_death_count = @as(u32, @intCast(else_mirrored_deaths.items.len));1277 const else_death_count = @as(u32, @intCast(else_mirrored_deaths.items.len));
1278 try a.extra.ensureUnusedCapacity(gpa, std.meta.fieldNames(CondBr).len + then_death_count + else_death_count);1278 try a.extra.ensureUnusedCapacity(gpa, @typeInfo(CondBr).@"struct".field_names.len + then_death_count + else_death_count);
1279 const extra_index = a.addExtraAssumeCapacity(CondBr{1279 const extra_index = a.addExtraAssumeCapacity(CondBr{
1280 .then_death_count = then_death_count,1280 .then_death_count = then_death_count,
1281 .else_death_count = else_death_count,1281 .else_death_count = else_death_count,
src/Sema.zig+1-1
...@@ -34033,7 +34033,7 @@ pub fn getTmpAir(sema: Sema) Air {...@@ -34033,7 +34033,7 @@ pub fn getTmpAir(sema: Sema) Air {
34033}34033}
3403434034
34035pub fn addExtra(sema: *Sema, extra: anytype) Allocator.Error!u32 {34035pub fn addExtra(sema: *Sema, extra: anytype) Allocator.Error!u32 {
34036 const field_count = std.meta.fieldNames(@TypeOf(extra)).len;34036 const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len;
34037 try sema.air_extra.ensureUnusedCapacity(sema.gpa, field_count);34037 try sema.air_extra.ensureUnusedCapacity(sema.gpa, field_count);
34038 return sema.addExtraAssumeCapacity(extra);34038 return sema.addExtraAssumeCapacity(extra);
34039}34039}
src/codegen/riscv64/encoding.zig+1-1
...@@ -498,7 +498,7 @@ pub const Instruction = union(Lir.Format) {...@@ -498,7 +498,7 @@ pub const Instruction = union(Lir.Format) {
498 extra: u32,498 extra: u32,
499499
500 comptime {500 comptime {
501 for (std.meta.fieldTypes(Instruction)) |field_type| {501 for (@typeInfo(Instruction).@"union".field_types) |field_type| {
502 assert(@bitSizeOf(field_type) == 32);502 assert(@bitSizeOf(field_type) == 32);
503 }503 }
504 }504 }
src/codegen/wasm/CodeGen.zig+1-1
...@@ -567,7 +567,7 @@ fn addCallIntrinsic(cg: *CodeGen, intrinsic: Mir.Intrinsic) error{OutOfMemory}!v...@@ -567,7 +567,7 @@ fn addCallIntrinsic(cg: *CodeGen, intrinsic: Mir.Intrinsic) error{OutOfMemory}!v
567/// Appends entries to `mir_extra` based on the type of `extra`.567/// Appends entries to `mir_extra` based on the type of `extra`.
568/// Returns the index into `mir_extra`568/// Returns the index into `mir_extra`
569fn addExtra(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {569fn addExtra(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {
570 const field_count = std.meta.fieldNames(@TypeOf(extra)).len;570 const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len;
571 try cg.mir_extra.ensureUnusedCapacity(cg.gpa, field_count);571 try cg.mir_extra.ensureUnusedCapacity(cg.gpa, field_count);
572 return cg.addExtraAssumeCapacity(extra);572 return cg.addExtraAssumeCapacity(extra);
573}573}
src/codegen/x86_64/CodeGen.zig+1-1
...@@ -1301,7 +1301,7 @@ fn addInst(self: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {...@@ -1301,7 +1301,7 @@ fn addInst(self: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
1301}1301}
13021302
1303fn addExtra(self: *CodeGen, extra: anytype) Allocator.Error!u32 {1303fn addExtra(self: *CodeGen, extra: anytype) Allocator.Error!u32 {
1304 const field_count = std.meta.fieldNames(@TypeOf(extra)).len;1304 const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len;
1305 try self.mir_extra.ensureUnusedCapacity(self.gpa, field_count);1305 try self.mir_extra.ensureUnusedCapacity(self.gpa, field_count);
1306 return self.addExtraAssumeCapacity(extra);1306 return self.addExtraAssumeCapacity(extra);
1307}1307}
src/link/Coff.zig+1-1
...@@ -3654,7 +3654,7 @@ fn verifyParentSectionAttributes(...@@ -3654,7 +3654,7 @@ fn verifyParentSectionAttributes(
3654 parent.name(coff).toSlice(coff),3654 parent.name(coff).toSlice(coff),
3655 });3655 });
36563656
3657 inline for (comptime std.meta.fieldNames(ObjectSectionAttributes)) |field| {3657 inline for (@typeInfo(ObjectSectionAttributes).@"struct".field_names) |field| {
3658 if (@field(child_attrs, field) != @field(parent_attrs, field)) {3658 if (@field(child_attrs, field) != @field(parent_attrs, field)) {
3659 err.addNote("flags.{s} was {d} in {s}, but {d} in {s}", .{3659 err.addNote("flags.{s} was {d} in {s}, but {d} in {s}", .{
3660 field,3660 field,
src/print_targets.zig+3-3
...@@ -43,9 +43,9 @@ pub fn cmdTargets(...@@ -43,9 +43,9 @@ pub fn cmdTargets(
43 {43 {
44 var root_obj = try serializer.beginStruct(.{});44 var root_obj = try serializer.beginStruct(.{});
4545
46 try root_obj.field("arch", meta.fieldNames(Target.Cpu.Arch), .{});46 try root_obj.field("arch", @typeInfo(Target.Cpu.Arch).@"enum".field_names, .{});
47 try root_obj.field("os", meta.fieldNames(Target.Os.Tag), .{});47 try root_obj.field("os", @typeInfo(Target.Os.Tag).@"enum".field_names, .{});
48 try root_obj.field("abi", meta.fieldNames(Target.Abi), .{});48 try root_obj.field("abi", @typeInfo(Target.Abi).@"enum".field_names, .{});
4949
50 {50 {
51 var libc_obj = try root_obj.beginTupleField("libc", .{});51 var libc_obj = try root_obj.beginTupleField("libc", .{});