Xo is experimental. The source code is not public yet; it will be soon. Read the release notes
Menu · Structs, enums, and newtypes

Docs

Structs, enums, and newtypes

types/main.xo

struct User {
  id: Int
  name: Str
  email: Str?
} derive Display

enum Shape {
  Circle(radius: Float)
  Rect(w: Float, h: Float)
  Point
}

fn area(s: Shape) -> Float {
  match s {
    Circle(radius) => 3.14159 * radius * radius
    Rect(w, h) => w * h
    Point => 0.0
  }
}

type UserId = Int
type Email struct(Str)

fn domain(e: Email) -> Str {
  e.0.split("@").last() ?? ""
}

fn main(os: Os) {
  let ada = User{id: 1, name: "Ada", email: None}
  let renamed = ada with {name: "Ada L."}
  os.stdio.println("${ada}")
  os.stdio.println("${renamed.name}")
  let id: UserId = 7
  os.stdio.println("user ${id}, area ${area(Shape.Rect(w: 2.0, h: 3.0))}")
  os.stdio.println(domain(Email("ada@example.com")))
}

Output:

User{id: 1, name: "Ada", email: None}
Ada L.
user 7, area 6.0
example.com
  • Constructing a struct names every field, so adding a field later is a compile error at every place that builds one.
  • u with {name: "..."} makes a modified copy. Structs are values.
  • Enums are sum types: each variant can carry its own fields, and match must handle every variant.
  • derive Display prints the value structurally. Json, Eq, Hash, and Ord are derived the same way.
  • type UserId = Int is an alias. type Email struct(Str) is a distinct type, so an Email can never be passed where a plain Str is expected by accident. Its value is e.0.