Array initialization, confusing error message

Hi.
Here is simple program.

$ cat p1.zig 

const std = @import("std");

const Object = struct {
    a: i32 = 7,
    b: i32 = 8,
};

pub fn main() void {
    const len = 3;
    var arr: [len]Object = [_]Object{.{}} ** len;
    std.debug.print("\n{any}\n", .{arr});
}

It works as expected:

$ ./p1 
{ p1.Object{ .a = 7, .b = 8 }, p1.Object{ .a = 7, .b = 8 }, p1.Object{ .a = 7, .b = 8 } }

However when I indicated the length of the array in initializer explicitly I got this:

$ /opt/zig/zig build-exe p1.zig 
p1.zig:11:39: error: expected 3 array elements; found 1
    var arr: [len]Object = [len]Object{.{}} ** len;
                           ~~~~~~~~~~~^~~~~

It seems I do not understand something… :frowning:
Why does explicit array length in initializing part causes this error?

could be a bug, did you try searching for issues?

No, I did not. I thought it would be better to ask here first before reporting a bug.

len is definitely comptime known, so it seems pretty obvious it is a bug. but i don’t see one when i search the issues.

no, i’m afraid it is not a bug but just a very confusing error message.

in the doc, the examples all show an empty array len [_] in initializers, so apparently that is the syntax for initializers, even though this is never stated explicitly

oops… I’ve already reported this as a bug (here). Ok, let’ see.

haha very funny

Yes, that means compiler will infer the length, if I get it right. But anyway I do not understand why explicit length results in such a strange error message. Where did compiler see one array element?

 = [_] Object{.{}} ** 3;
 = [3] Object{.{}} ** 3;

These two have absolutely the same look for me.
Probably the compiler treats the second one as one element, which is 3-element (or 9-element???) array by itself.

This variant is ok:

const std = @import("std");
const Object = struct {
    a: i32 = 7,
    b: i32 = 8,
};
pub fn main() void {
    const len = 3;
    var arr: [len]Object = [len]Object{.{}, .{}, .{}};
    std.debug.print("\n{any}\n", .{arr});
}

So it’s not explicit length in initializer, it’s length plus duplication (**).

As was explained to me, the point is that

[_]Object{.{}} ** len

means

([1]Object{.{}}) ** len
4 Likes