Struct cast to slice

I’m only a little surprised that this works:

const E = enum { a, b, c, };
pub fn farr(arr: []const E) void {
   std.debug.print("arr type: {s}\n", .{ @typeName(@TypeOf(arr)), }); // "slice", basically
}
test "array-or-struct" {
   const a = .{ .a, .b, };
   std.debug.print("a type: {s}\n", .{ @typeName(@TypeOf(a)), }); // "struct", basically
   //farr(a); // obviously can't do this
   farr(&a); // bit of a surprise
}

The advice I’d give to myself here is, “don’t do that. instead:

   const a = [_]E{ .a, .b, };

… if, of course, that’s what you really mean.” But it raises questions about whether this is how it should work – are there cases for… well, what I might call implicit casting from struct to slice? It doesn’t work everywhere; for instance, I can’t ++ that original a with a slice. But is this a “feature” I missed before? Or an accident to stay away from? Or…?

While it uses the struct keyword in the language syntax, Zig actually calls this a Tuple, and tuples do share some behavior with arrays/slices, they have a len field, can be iterated with inline for loops and support ++ and ** (as long the other type matches). So it also makes sense that this coercion exists.

Generally I think the preferred way is const a: [2]E = .{...};, see also this proposal: remove T{} syntax in favor of type coercion · Issue #5038 · ziglang/zig · GitHub

2 Likes

FWIW I’d love to have tuples behave more like arrays and coerce to them more readily, e.g. both this:

const a: u32 = 123;
const b: u32 = 456;
for (.{ a, b }) |i| { _ = i; }

and this:

const a: u32 = 123;
const b: u32 = 456;
for (&.{ a, b }) |i| { _ = i; }

will currently throw:

error: unable to resolve comptime value
for (.{ a, b }) |i| { _ = i; }
     ~^~~~~~~~
note: tuple field index must be comptime-known

instead of just coercing to [2]u32 or *const [2]u32 respectively which would be really nice IMO.

I think homogenous tuples even having the same memory layout as arrays is the de-facto status quo but it’s not (yet?) formalized (though the coercion from tuple to array/slice is already guaranteed to work).

1 Like

I wanted to reference this earlier thread, “Are Tuples Structs?“ by @mnemnion as well, for posterity.

1 Like