@sizeOf anonymous type returns zero?

I was working on a toy project and bumped into behavior that I don’t fully understand. In certain cases, @sizeOf doesn’t work as I’d expect, specifically when passing an anonymous struct:

const S = struct {
    color: [4]f32,
};

fn getSize(p: anytype) usize {
    return @sizeOf(@TypeOf(p));
}

test "sizeof " {
    // These work.
    try std.testing.expectEqual(4, getSize(@as(u32, 1)));
    try std.testing.expectEqual(16, getSize([4]f32{ 1.0, 0.0, 0.0, 1.0 }));
    try std.testing.expectEqual(16, getSize(S{ .color = [4]f32{ 1.0, 0.0, 0.0, 1.0 } }));

    // For these, @sizeOf returns 0.
    try std.testing.expectEqual(16, getSize(.{ .color = [4]f32{ 1.0, 0.0, 0.0, 1.0 } }));
    try std.testing.expectEqual(16, getSize(.{ .color = .{ 1.0, 0.0, 0.0, 1.0 } }));
}

// ❯ zig version 
// 0.15.1

Is there a reasonable explanation for this or I’m just holding it wrong?
My understanding is that anonymous structs supposed to act the same way as regular ones (with the exception that the compiler assigns their names).

My assumption is that those types are comptime and for that you get 0:

This function measures the size at runtime. For types that are disallowed at runtime, such as comptime_int and type, the result is 0.

Try forcing them to runtime by referencing them?

When you do

@compileLog(@typeInfo(@TypeOf(p)).@"struct".fields);

you see that they are comptime fields:

@as([]const builtin.Type.StructField, &.{ .{ .name = "color"[0..5], .type = [4]f32, .default_value_ptr = &.{ 1, 0, 0, 1 }, .is_comptime = true, .alignment = 4 } }[0..1])
@as([]const builtin.Type.StructField, &.{ .{ .name = "color"[0..5], .type = struct { comptime comptime_float = 1, comptime comptime_float = 0, comptime comptime_float = 0, comptime comptime_float = 1 }, .default_value_ptr = &.{ 1, 0, 0, 1 }, .is_comptime = true, .alignment = 1 } }[0..1])
2 Likes

Try forcing them to runtime by referencing them?

Interesting…

    const x = .{ .color = [4]f32{ 1.0, 0.0, 0.0, 1.0 } };

    // This works!
    try std.testing.expectEqual(16, getSize(x.color));

    // But this doesn't
    try std.testing.expectEqual(16, getSize(x));

So it looks like I can’t just take anytype. I need to be aware that someone (in case of a public library) might pass an anonymous type.

I’m not sure anytype is the issue, the issue is that they’re comptime and therefore have no size at runtime.

4 Likes

You could assert the size of the anytype parameter is something you expect, wherever you actually use it in your real code, giving people an error if they try to use it with a wrong type in safe modes.

From @sizeOf:

This function measures the size at runtime. For types that are disallowed at runtime, such as comptime_int and type, the result is 0.

3 Likes

If you are checking information about a type it is comptime known, regardless of mode you will get a compile error. Modes are for runtime checks/optimisations not compile time.

I know you know this, just pointing that out for others.

1 Like

Most likely the assertion can happen at comptime when it is based on some constant or calculation that fully depends on other comptime known things and in those case modes don’t matter.

My answer was more general, also including cases where part of the assert would be runtime known, for example when you assert that some runtime slice is smaller than the size of some array.

1 Like