Proposal A — a union declaration
Status: leaning · See the section overview for the question all three answer
The idea: a named union declaration lists its members like struct fields,
name: Type, each tagged with @id. A member can also declare its fields
inline, which creates an anonymous struct.
Shape
struct Attack {
target: u32
}
union EntityAction {
@id = 0x00
attack: Attack
@id = 0x01
interact(target: u32, hand: Hand) // inline fields
@id = 0x02
interact_at(target: u32, hand: Hand, x: f32, y: f32, z: f32)
@id = 0x03
swing // no payload
}
Generated:
pub enum EntityAction {
Attack(Attack),
Interact { target: u32, hand: Hand },
InteractAt { target: u32, hand: Hand, x: f32, y: f32, z: f32 },
Swing,
}
type EntityAction =
| { kind: "attack"; value: Attack }
| { kind: "interact"; target: number; hand: Hand }
| { kind: "interact_at"; target: number; hand: Hand; x: number; y: number; z: number }
| { kind: "swing" };
The case for it
- Enums stay simple. They remain named values, which is what phases
(
@phases),@open, explicit numeric values and C-style protocols need. No rule has to forbid data on some enums. - Members read like struct fields.
name: Typeis already known, and Protobuf'soneofworks the same way. - Tags reuse
@id, the mechanism functions already have. - The name matches the result in TypeScript, where it's a discriminated union, and the word people from C and Protobuf expect.
- A union of existing types needs no wrapper.
value: Valueortext: stringnames a type that already exists, without declaring a struct per member.
The case against
unionwould mean two things: the inline untaggedunion(A B)and the declared tagged one. The inline form needs a decision (see the overview).- It overlaps with enums at the edges. A union whose members all have no payload is an enum with extra steps. Should that be a warning suggesting an enum?
- Rust users expect data on enum variants and may look for it there first.
- Inline fields are a second way to write a member's payload beside naming a type. Without them, every payload needs its own struct.
When this would be the right call
When enums should stay the plain, numeric-friendly construct that phases and packet protocols lean on, and "one of these shapes" is worth its own word.