Enums and Match

Lux enums are designed for two different jobs:

  • scalar enums give names to stable primitive values;
  • table enums model tagged values that carry fields.

match uses the enum shape to produce direct Lua comparisons while still giving the compiler enough information to report missing cases.

Scalar Enums Are Zero-runtime by Default

A scalar enum with a numeric representation lowers to numbers. No runtime enum table is required unless you explicitly ask for one.

number enum compiles to numeric comparisons
enum FillKind repr number {
  Solid = 0,
  Linear = 1,
  Radial = 2,
}

local mode = match kind {
  FillKind.Solid => "solid"
  FillKind.Linear => "linear"
  FillKind.Radial => "radial"
}

String-backed scalar enums lower to string comparisons.

string enum compiles to string comparisons
enum DockMode repr string {
  Left = "left",
  Right = "right",
}

local side = match dock {
  DockMode.Left => 0
  DockMode.Right => 1
}

Use scalar enums when the value needs to cross net messages, files, convars, or plain GLua APIs.

Runtime Scalar Enums

runtime asks Lux to emit a table for reflection or external API compatibility.

runtime enum can be exported
export runtime enum HudState repr string {
  Hidden = "hidden",
  Compact = "compact",
  Full = "full",
}

The runtime marker can also appear after the representation if that reads better with surrounding declarations.

runtime postfix form
enum Channel repr number runtime {
  System = 0,
  User = 1,
}

Without runtime, scalar enum member names are compile-time names only.

Table Enums

Table enums create tagged tables. Use them when each case has different data.

table enum constructors
enum DrawCommand repr table {
  Rect { x, y, w, h, color }
  Text { x, y, text, font }
}

local cmd = DrawCommand.Rect {
  x = 0,
  y = 0,
  w = 100,
  h = 20,
  color = Color(255, 255, 255),
}

Matching a table enum narrows the fields available in each branch.

table enum match
match cmd {
  DrawCommand.Rect { x, y, w, h, color } => {
    draw.RoundedBox(0, x, y, w, h, color)
  }
  DrawCommand.Text { x, y, text, font } => {
    draw.SimpleText(text, font, x, y)
  }
}

The default table tag key is compiler-owned. Code should construct values through the generated constructors instead of writing tags by hand.

Existing Views

An existing view describes externally-created values without generating constructors. This is useful for GMod or third-party tables that already carry a stable tag field.

existing view creates no constructors
enum NetMessage repr existing table tag "kind" {
  Inventory { itemId, count }
  Chat { text }
}

match msg {
  NetMessage.Inventory { itemId, count } => addItem(itemId, count)
  NetMessage.Chat { text } => chat.AddText(text)
}

existing views are type-level knowledge for the compiler; they do not change the source tables.

Fallback and _

Use _ for a fallback branch when the value space is open or when you intentionally do not handle every case.

Fallback branch
local label = match state {
  HudState.Hidden => "hidden"
  HudState.Compact => "compact"
  _ => "other"
}

Fallback branches should be used deliberately. When matching a closed enum, leaving out a case without _ is usually a bug.

match Checking Rules

Lux checks match at compile time when the matched value has an enum availability. Missing cases are diagnostics unless a fallback branch exists.

Non-exhaustive match
enum Tab repr string {
  Home = "home",
  Settings = "settings",
  Profile = "profile",
}

local title = match tab {
  Tab.Home => "Home"
  Tab.Settings => "Settings"
}

For scalar enums, branches compare the underlying scalar value. For table enums, branches compare the tag and then bind fields.

Realms and Enums

Enum declarations have realms like other bindings. Exporting an enum cannot make it available in a wider realm than the enum binding itself.

Enum export cannot expand realms
server enum ServerOnly repr string {
  Grant = "grant",
}

export shared { ServerOnly }

Shared scalar enums are often the right shape for network protocol constants. Server-only or client-only enums are better for local implementation state.