How to initialize an array with union element?

In the following code, test 1 passed, but test 2 doesn’t.

const std = @import("std");

test "1" {
	const T = union(enum) {
		a: void,
		b: u8,
	};

	const ts: [256]T = .{.a} ** 256;
	std.debug.assert(ts[0] == .a);
}

test "2" {
	const T = union(enum) {
		a: bool,
		b: u8,
	};

	const ts: [256]T = .{.a = false} ** 256;
	std.debug.assert(ts[0] == .a);
}
1 Like

You’re only missing one more set of braces. You need to initialize the array with a union being initialized within that:

const ts: [256]T = .{ .{.a = false} } ** 256;
3 Likes

Aha, thanks! Interesting, I must miss something, why does test 1 pass?

That doesn’t even compile for me on godbolt - I get:

example.zig:10:29: error: coercion from enum '@TypeOf(.enum_literal)' to union 'example.bar__union_896' must initialize 'bool' field 'a'

Maybe someone else can run this in using zig test and tell me what they get? Also, what Zig version are you on?

In the first test the a union type is not bool, it is void. In 0.12 it compiles, probably because .{.a} is the same as .{a = {}}

1 Like

I use version 0.13.0-dev.8+c352845e8.

This is the most unexpected zig syntax I have ever see.

test "2" {
    const T = union(enum) {
        a: bool,
        b: u8,
    };

    const t: T = .{ .a = false };
    const ts: [256]T = t ** 256;
    std.debug.assert(ts[0] == .a);
}

fails with:

error: expected indexable; found 'test.test.2.T'
    const ts: [256]T = t ** 256;
                       ^

but t is already a T union.

EDIT: by changing t to a single element array it becomes indexable.

test "2" {
    const T = union(enum) {
        a: bool,
        b: u8,
    };

    const t = [1]T{T{ .a = false }};
    const ts: [256]T = t ** 256;
    std.debug.assert(ts[0] == .a);
}
2 Likes

Also, this is an important distinction about the void type. This compiles with void:

const ts: [256]T = .{.a} ** 256;

Because it’s interpreting the .{...} as an array and then implicitly constructs a. That’s a sneaky piece of syntax.

3 Likes

Do you mean .{.a} is implicitly transformed to .{.{.a = {}}} or .{.{.a = .{}}}? (Really sneaky.)

Yeah, so…

.{..} → initialize array
.a → initialize void union member

Thus…

.{ .{ .a = void{} } }

1 Like

I do hope your old code

test "2" {
    const T = union(enum) {
        a: bool,
        b: u8,
    };

    const t = T{ .a = false };
    const ts: [256]T = t ** 256;
    std.debug.assert(ts[0] == .a);
}

works.

I always use the 1 element array

const ts: [256]T = [1]T{ .{ .a = false } } ** 256;
4 Likes