Enums & Pattern Matching

Enums were added in Sui Move 2024 and Aptos Move 2.0.

Enums were added in Sui Move 2024 and Aptos Move 2.0. They allow a type to be one of several variants, each optionally carrying data.

21.1 Declaring enums

// Sui Move 2024
public enum Status has copy, drop, store {
    Pending,
    Active { since_ms: u64 },
    Closed(u64),              // positional variant
}

// Aptos Move 2
enum Shape has copy, drop, store {
    Circle { radius: u64 },
    Rectangle { width: u64, height: u64 },
}

21.2 Constructing and matching

// Sui
public fun activate(now: u64): Status { Status::Active { since_ms: now } }

public fun describe(s: &Status): u64 {
    match (s) {
        Status::Pending => 0,
        Status::Active { since_ms } => *since_ms,
        Status::Closed(code) => *code,
    }
}
// Aptos
public fun area(s: &Shape): u64 {
    match (s) {
        Shape::Circle { radius } => 3 * *radius * *radius,
        Shape::Rectangle { width, height } => *width * *height,
    }
}

// Aptos also supports variant tests and common field access:
public fun is_circle(s: &Shape): bool { s is Shape::Circle }

21.3 Match features

match (x) { 0 =>.., 1 =>.., _ =>.. } Status::Closed(c) if (*c > 10) =>.. Bindings with mut

Status::Active { mut since_ms } =>.. (Sui, by value) Status::Pending | Status::Closed(_) =>..

Compiler requires all variants to be covered

21.4 Enum rules

Like structs, enums can only be constructed, matched, and destructured inside their defining module.

Enums cannot have the key ability (they cannot be top-level objects/resources), but they can live inside structs that do.

Upgrading: on Sui, a published enum's variants are part of its layout and cannot be removed, reordered, or extended in a compatible upgrade — plan variants up front (or wrap evolving data in dynamic fields). Aptos Move allows appending new variants at the end in compatible upgrades. Always check your chain's current upgrade rules before relying on enum evolution.

21.5 State machine example

// Sui Move 2024
public enum OrderState has copy, drop, store {
    Created,
    Paid { amount: u64 },
    Shipped { tracking: vector<u8> },
    Delivered,
}

const EInvalidTransition: u64 = 1;

public fun advance(state: OrderState, input: u64): OrderState {
    match (state) {
        OrderState::Created => OrderState::Paid { amount: input },
        OrderState::Paid { amount: _ } => OrderState::Shipped { tracking: b"TRK" },
        OrderState::Shipped { tracking: _ } => OrderState::Delivered,
        OrderState::Delivered => abort EInvalidTransition,
    }
}