# Enums and match

> Plain enums, enums whose variants carry data, methods on enums, recursive enums, every kind of match pattern, guards, and the exhaustiveness check.

Source: https://docs.brinelang.org/language/enums-and-match/

An enum is a type whose value is one of a fixed set of *variants*, each of which may carry its own named fields. You read a variant’s data with `match`, and every `match` must handle every possible value: the compiler checks this and shows you a value you missed ([E0320](/reference/errors/#e0320)).

## Defining enums

[Section titled “Defining enums”](#defining-enums)

A variant is a plain tag (`Red`) or carries fields (`Circle(radius: float)`). Enums can have methods, defined inside them like a struct’s.

```brine
enum Color:
    Red
    Green
    Blue


enum Shape:
    Circle(radius: float)
    Rect(w: float, h: float)
    Empty


    fn area(self) -> float:
        match self:
            case Shape.Circle(r):
                return 3.14 * r * r
            case Shape.Rect(w, h):
                return w * h
            case Shape.Empty:
                return 0.0


fn main():
    let c = Color.Green
    print(c, c == Color.Red)
    let shapes = [Shape.Circle(1.0), Shape.Rect(w=2.0, h=3.0), Shape.Empty]
    for s in shapes:
        print(s, s.area())
    print(shapes[1] == Shape.Rect(2.0, 3.0))
```

Output

```text
Color.Green false
Shape.Circle(radius=1.0) 3.14
Shape.Rect(w=2.0, h=3.0) 6.0
Shape.Empty 0.0
true
```

* Variants are always written with the enum’s name: `Color.Red`, `Shape.Circle(1.0)`. (The exception is the built-in `Option` and `Result`, whose `Some`, `None`, `Ok` and `Err` stand alone; see [Option and Result](/language/error-handling/).)
* Construct a variant with data positionally or by keyword, like a struct: `Shape.Rect(2.0, 3.0)` or `Shape.Rect(w=2.0, h=3.0)`.
* Enum values print as `Enum.Variant(field=value, ...)` and compare with `==` and `!=`.
* Methods work as on [structs](/language/structs/#methods): `self`, `ref self`, or no `self` for a static method. An enum’s fields can’t be changed in place; a `ref self` method changes the value by assigning a whole new one (`self = Light.Off`).
* Enums are values: copying one copies it.

## Reading variant data

[Section titled “Reading variant data”](#reading-variant-data)

Variant data can only be read with `match`, never with `.field`, because the field exists only in some variants:

```brine
enum Shape:
    Circle(radius: float)
    Empty


fn main():
    let s = Shape.Circle(2.0)
    print(s.radius)
```

```text
error[E0205]: enum `Shape` has no fields
 --> main.br:7:13
  |
7 |     print(s.radius)
  |             ^^^^^^ use `match` to read the data in a variant
  = run `brine explain E0205` for more about this error
error: could not compile due to 1 error
```

## Recursive enums

[Section titled “Recursive enums”](#recursive-enums)

A variant may contain its own enum, so trees and expressions need no extra machinery:

```brine
enum Expr:
    Num(value: int)
    Add(left: Expr, right: Expr)
    Mul(left: Expr, right: Expr)


fn eval(e: Expr) -> int:
    match e:
        case Expr.Num(v):
            return v
        case Expr.Add(l, r):
            return eval(l) + eval(r)
        case Expr.Mul(l, r):
            return eval(l) * eval(r)


fn main():
    let e = Expr.Add(Expr.Num(2), Expr.Mul(Expr.Num(3), Expr.Num(4)))
    print(eval(e))
    print(e)
```

Output

```text
14
Expr.Add(left=Expr.Num(value=2), right=Expr.Mul(left=Expr.Num(value=3), right=Expr.Num(value=4)))
```

Enums can be generic too (`enum Tree[T]:`); see [generics](/language/generics/).

## match

[Section titled “match”](#match)

`match value:` is followed by `case pattern:` blocks. The first case whose pattern matches runs; there is no fall-through. `match` is a statement (it doesn’t produce a value), so assign or `return` inside the cases.

## Patterns

[Section titled “Patterns”](#patterns)

```brine
enum Shape:
    Circle(radius: float)
    Rect(w: float, h: float)
    Empty


enum Expr:
    Num(value: int)
    Add(left: Expr, right: Expr)
    Neg(inner: Expr)


fn size(n: int) -> str:
    match n:
        case 0:                          # a literal
            return "none"
        case 1 | 2 | 3:                  # alternatives
            return "a few"
        case k if k < 0:                 # a capture with a guard
            return f"invalid ({k})"
        case _:                          # anything else
            return "many"


fn where(p: (int, int)) -> str:
    match p:
        case (0, 0):
            return "origin"
        case (0, _) | (_, 0):            # alternatives (no names inside)
            return "on an axis"
        case (x, y) if x == y:
            return f"on the diagonal at {x}"
        case _:
            return "elsewhere"


fn describe(e: Expr) -> str:
    match e:
        case Expr.Num(0):                                # a literal inside a variant
            return "zero"
        case Expr.Add(Expr.Num(a), Expr.Num(b)):         # nested variants
            return f"{a} + {b}"
        case Expr.Neg(Expr.Neg(inner=x)):                # keyword field pattern
            return f"double negation of {x}"
        case Expr.Add(left=l):                           # just the fields you need
            return f"a sum starting with {l}"
        case _:
            return "something else"


fn tall(s: Shape) -> bool:
    match s:
        case Shape.Rect(h=h) if h > 10.0:
            return true
        case _:
            return false


fn main():
    for n in [0, 2, -5, 99]:
        print(size(n))
    print(where((0, 0)), where((0, 7)), where((3, 0)), where((2, 2)), where((1, 3)))
    print(describe(Expr.Num(0)))
    print(describe(Expr.Add(Expr.Num(1), Expr.Num(2))))
    print(describe(Expr.Neg(Expr.Neg(Expr.Num(5)))))
    print(describe(Expr.Add(Expr.Num(1), Expr.Neg(Expr.Num(2)))))
    print(tall(Shape.Rect(1.0, 20.0)), tall(Shape.Circle(30.0)))
    match "go":
        case "stop":
            print("stopping")
        case "go":
            print("going")
        case _:
            print("unknown command")
```

Output

```text
none
a few
invalid (-5)
many
origin on an axis on an axis on the diagonal at 2 elsewhere
zero
1 + 2
double negation of Expr.Num(value=5)
a sum starting with Expr.Num(value=1)
true false
going
```

| Pattern                    | Matches                                                                                                    |
| -------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `_`                        | anything, and binds nothing                                                                                |
| `name`                     | anything, and binds it to `name` (a capture)                                                               |
| `0`, `"go"`, `true`        | that integer, string or bool literal                                                                       |
| `(a, 0)`                   | a tuple whose parts match, element by element                                                              |
| `p1 \| p2 \| p3`           | any of the alternatives; they can’t bind names ([E0321](/reference/errors/#e0321)), so use `_` inside them |
| `Shape.Rect(w, _)`         | that variant, with its fields matched in order                                                             |
| `Expr.Add(left=l)`         | that variant, with the named fields matched and the rest ignored                                           |
| `Expr.Add(Expr.Num(a), _)` | variants nested in variants, to any depth                                                                  |
| `pattern if condition`     | the pattern, and then only if the condition (which can use its captures) is true                           |

A capture is a new variable, so it follows the [no-shadowing rule](/language/bindings/#no-shadowing): it can’t reuse the name of a variable that is already in scope. Captures in different `case`s may share a name.

A bare variant name is a capture

In a pattern, `Red` on its own is a new variable named `Red` that matches anything, not the variant `Color.Red`. Always write the enum’s name:

```brine
enum Color:
    Red
    Green


fn main():
    let c = Color.Green
    match c:
        case Red:
            print("red")
        case Green:
            print("green")
```

This prints `red`. The compiler warns that the second case can never be reached:

```text
warning[W0002]: this case can never be reached
  --> main.br:10:9
   |
10 |         case Green:
   |         ^^^^^^^^^^ unreachable
   |
   = help: an earlier `case` already matches every value
   = run `brine explain W0002` for more about this error
```

Write `case Color.Red:` and `case Color.Green:`.

## Exhaustiveness

[Section titled “Exhaustiveness”](#exhaustiveness)

Every `match` must handle every possible value. When it doesn’t, the error shows a value that no case handles, so a new enum variant can never slip through unnoticed:

```brine
enum Shape:
    Circle(radius: float)
    Rect(w: float, h: float)
    Empty


fn area(s: Shape) -> float:
    match s:
        case Shape.Circle(r):
            return 3.14 * r * r
        case Shape.Empty:
            return 0.0


fn main():
    print(area(Shape.Empty))
```

```text
error[E0320]: this `match` doesn't handle every possible value
 --> main.br:7:11
  |
7 |     match s:
  |           ^ of type `Shape`
  |
  = note: not handled: `Shape.Rect(_, _)`
  = help: add `case Shape.Rect(_, _):`, or a catch-all `case _:`
  = run `brine explain E0320` for more about this error
error: could not compile due to 1 error
```

The check looks inside tuples and nested variants too: matching `(true, _)` and `(false, true)` on a `(bool, bool)` reports `(false, false)` as not handled.

Cases with a guard don’t count, because the guard may be false. Integers and strings have too many values to list, so a `match` on them always needs `case _:` (or a plain capture, which matches everything):

```brine
fn main():
    let n = 4
    match n:
        case 0:
            print("zero")
        case k if k > 0:
            print("positive")
```

```text
error[E0320]: this `match` doesn't handle every possible value
 --> main.br:3:11
  |
3 |     match n:
  |           ^ of type `int`
  |
  = note: cases with an `if` guard don't count, since the guard may be false
  = help: add a catch-all `case _:` at the end
  = run `brine explain E0320` for more about this error
error: could not compile due to 1 error
```

A case that can never be reached because earlier cases already match everything it would is the warning W0002.

## Summary

[Section titled “Summary”](#summary)

* `enum Name:` lists variants: plain tags or `Variant(field: Type, ...)`. Enums can have methods, be recursive and be generic.
* Write variants with the enum’s name, in expressions and in patterns.
* Read variant data with `match`, never `.field`.
* Patterns: `_`, captures, literals, tuples, `|` alternatives (no names inside), variants with positional or keyword fields, nested to any depth, and `if` guards.
* `match` must be exhaustive (E0320); guarded cases don’t count; integers and strings need `case _:`.
