Skip to content

Unions

Unions are discriminated (tagged) variant types. Each case has a zero-based index that serves as the wire discriminator.

Basic Syntax

union Shape {
    Circle(radius: f4),
    Rectangle(width: f4, height: f4),
    Triangle(a: f4, b: f4, c: f4)
}

Each case is assigned a sequential index: Circle = 0, Rectangle = 1, Triangle = 2.

Shared Fields (Base Arguments)

Unions can declare shared fields that are present in every case:

union ApiResponse(requestId: u4, timestamp: datetime) {
    Success(data: bytes),
    NotFound(path: string),
    Error(code: i4, message: string)
}

requestId and timestamp are available in all three cases.

Type Reference Cases

Cases can reference existing types instead of declaring inline fields:

msg UserData { name: string; age: u1; }
msg ErrorInfo { code: i4; message: string; }

union Result {
    UserData,
    ErrorInfo
}

Unions with type reference cases cannot declare shared fields. Doing so triggers ION0012.

Wire Format & Discriminator

Unions are serialized as a CBOR array where the first element is the discriminator index:

// Shape.Rectangle(width: 10, height: 20)
[1, 10.0, 20.0]   // discriminator=1 (Rectangle), then fields

// Shape.Circle(radius: 5)
[0, 5.0]           // discriminator=0 (Circle), then fields

Reordering union cases is a breaking change — it shifts the discriminator index. Detected by ION0028.

Generated Code

In C#, unions generate an interface marked with IIonUnion<T> and sealed classes for each case:

public interface Shape : IIonUnion<Shape>
{
    public sealed class Circle : Shape
    {
        public float radius { get; set; }
    }

    public sealed class Rectangle : Shape
    {
        public float width { get; set; }
        public float height { get; set; }
    }
}