What is an anonymous struct used for?
For example in std.debug.print a required argument is an anonymous struct but how does it relate?
Here is some examples:
// Declare named structs.
const NamedStruct = struct { x: usize, y: usize };
test "structs" {
// Use named struct, set x and y.
const named_data: NamedStruct = .{ .x = 1, .y = 2 };
// Print named struct fields
std.debug.print("Fields {d} {d}\n", .{ named_data.x, named_data.y });
// Made up anonymous struct, not defined anywhere except in this line:
std.debug.print("Define here: c: {d}, d: {d}\n", .{ .cat = 3, .dog = 4 });
// yet often takes other ramdom variables instead
const feline = 30;
const canine = 40;
std.debug.print("Variables passed: c: {d}, d: {d}\n", .{ feline, canine });
// Anonymous structs often match to function struct parameters.
call_something1(.{ .width = 100, .height = 200 });
call_something2(.{ .x = 100, .y = 200 });
}
// Struct could be named as "Measurements", but here decided as anonymous.
pub fn call_something1(data: struct { width: usize, height: usize }) void {
std.debug.print("Got struct fields: w {d}, h: {d}\n", data);
}
// Takes named struct, as most functions do.
pub fn call_something2(data: NamedStruct) void {
std.debug.print("Got named struct: x: {d}, y: {d}\n", data);
}
Anonymous structs are way to not-need-to name all structs passed/used, e.g. if they are used only once/locally/setup, or like for std.debug.print that checks fields given at compile time as parameter change all the time, as you use it debug different things.
If data fields are used more widely in software and passed around e.g. to lists, obviously use named structs for clarity and documentation.
Specifically for functions like std.debug.print, or other formatting functions, there needs to be a way to provide a psuedo-variadic call. An anonymous struct (in this case anyval) allows for any shaped struct to be provided, which can then be used for any kind of format string.
Note that while the struct may be anonymous, it isn’t required to be. You can also do something like this:
const Foo = struct {
bar: i8 = 0,
baz: u8 = 255
};
pub fn main() void {
const x: Foo = .{};
std.debug.print("bar: {[bar]d}, baz: {[baz]x}", x);
}
Could one argue that anonymous structs are used for everything struct related in zig? And only by accident it is also possible to bind a name to a struct type?
Any way here some experiments from my side:
const std = @import("std");
const Foo = struct {
bar: u8,
baz: u8,
};
// struct instance with some anonymous type
const aa = .{ .bar = 5, .baz = 6 };
// struct instance with specific Foo type
const bb: Foo = .{ .bar = 5, .baz = 6 };
// tuple instance with some anonymous type
// some special form of struct in zig AFAICT. With some interesting properties.
const cc = .{ 5, 6 };
pub fn main() !void {
// print our struct contents
std.debug.print("bar: {} baz: {}\n", aa);
std.debug.print("bar: {} baz: {}\n", bb);
std.debug.print("0: {} 1: {}\n", cc);
// now lets do it flipped by referencing the field names
std.debug.print("baz: {[baz]} bar: {[bar]}\n", aa);
std.debug.print("baz: {[baz]} bar: {[bar]}\n", bb);
std.debug.print("1: {[1]} 0: {[0]}\n", cc);
// lets find out about types
std.debug.print("aa type: {}\n", .{@TypeOf(aa)});
std.debug.print("bb type: {}\n", .{@TypeOf(bb)});
std.debug.print("cc type: {}\n", .{@TypeOf(cc)});
// and print all info from the type
// That would have been nice but something is not working in the formater
// code not sure if std is broken or I don't get it.
//std.debug.print("{}\n", .{@typeInfo(@TypeOf(aa))});
//std.debug.print("{}\n", .{@typeInfo(@TypeOf(bb))});
//std.debug.print("{}\n", .{@typeInfo(@TypeOf(cc))});
}