Skip to content
Saule
Docs

Enums

enum Direction
North
South
East
West
end
local d: Direction = Direction.North
enum Status
Alive = "alive"
Dead = "dead"
Unknown = "unknown"
fn describe() -> string
return "Status is: " .. self.value
end
end
local s: Status = Status.Alive
print(s.describe()) -- "Status is: alive"
enum Direction
North
South
end
class Walker
y: integer = 0
fn move(dir: Direction) -> nil
if dir == Direction.North then
self.y = self.y + 1
end
end
end
local w: Walker = Walker()
w.move(Direction.North)
println(w.y) -- 1

An enum takes type parameters the same way, and a variant’s payload may be typed by one. This is what makes a Result worth writing: the arm that matches Ok binds a real T, not an any you have to cast:

enum Result<T>
Ok(value: T),
Err(message: string)
end
local r: Result<integer> = Result.Ok(5)
local n: integer = match r
case Result.Ok(v) then v + 1 -- `v` is an `integer`
case Result.Err(m) then 0
end

The instantiation comes from the construction where the payload pins it down, and from the annotation where it doesn’t — Result.Err("boom") says nothing about T, so it fits any Result:

enum Result<T>
Ok(value: T)
Err(message: string)
end
local inferred = Result.Ok("hi") -- Result<string>
local failed: Result<integer> = Result.Err("boom")
println(match inferred case Result.Ok(v) then v case Result.Err(m) then m end) -- hi

Exhaustiveness is unaffected: type arguments say what the payloads hold, never which variants exist.