# Structs, enums, and newtypes


`types/main.xo`

```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:

```text
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`.

