zig icon indicating copy to clipboard operation
zig copied to clipboard

Proposal: `packed struct(Backing)` -> `packed(Backing) struct`, support `packed(Backing) union`

Open rohlem opened this issue 11 months ago • 7 comments

Background

In status-quo, packed struct and packed union types are guaranteed to occupy the minimum number of bits required. For packed struct this is the sum of the number of bits of their fields, for packed union (which status-quo requires to be untagged), it's the maximum number of bits of its states.

Status-quo allows the syntax packed struct(Backing) to specify the backing integer type, which is a convenient way to have the compiler assert the number of bits occupied. (side note: currently undocumented in the corresponding langref section.) I think the same mechanism would be useful to have for packed union types.

I assume the reason this is currently not supported by the language is that union(X) is used to specify X as the tag type, and overloading it to instead specify X as the backing type in packed union(X) would be confusing.

Proposal

I propose the backing type to instead become the syntactic "argument" of the packed keyword. With this, status-quo packed struct(Backing) becomes packed(Backing) struct, and packed(Backing) union becomes unambiguously expressible.

I then secondly propose supporting packed(Backing) union in the language. std.builtin.Type.Union would have to gain field backing_integer: ?type from std.builtin.Type.Struct in order for @typeInfo and @Type to integrate with this additional information.

Potential drawbacks

This slightly reduces grep-ability for packed struct syntax - I'm not sure how often this comes up in workflows. If that is a concern, a mitigation against this would be to order packed after the container type, yielding f.e. struct packed, struct packed(u16), union packed(u12).

rohlem avatar Mar 22 '24 14:03 rohlem

Small bikeshed: I think it would make sense to make ContainerLayout be a tagged union, wherein the @"packed" member is of type type, as for any state where the layout isn't packed, it's illegal to specify the backing_integer type - unless specifying null for .@"packed" is made to mean "infer the backing type", as is what happens for field alignment = 0.

InKryption avatar Mar 22 '24 19:03 InKryption

@InKryption Sure, that's a larger change than necessary for the proposal, but it does better reflect the logic of status-quo. Note that this would require reverting should the language ever allow an explicitly-sized extern type, f.e. packed(u16) extern struct, in the future.

rohlem avatar Mar 22 '24 19:03 rohlem

I dont read packed struct(T) as T modifying the struct keyword. packed struct is a single entity kind that doesnt need parentheses to be instantiated. inline fn is another example.

nektro avatar Mar 22 '24 19:03 nektro

if this were to change I'd prefer struct packed(T) but I feel that needlessly hurts readability.

nektro avatar Mar 22 '24 19:03 nektro

  • What if packed struct was |_| struct

    • What if packed(backingInt) struct was |backingInt| struct

If this syntax is already used to capture values, maybe it can go in the other direction of wrangling them too.

That won't work. It makes the syntax require lookaheads and looks terribly inconsistent overall.

sin-ack avatar Mar 22 '24 20:03 sin-ack

bits {...}

expikr avatar Mar 23 '24 03:03 expikr

bits sounds incredibly vague, and doesn't solve the problem in the original issue.

sin-ack avatar Mar 23 '24 08:03 sin-ack