# Pattern matching

> Turn continuous values into named cases with match expressions and statements.

`match` compares one value against ordered cases. It suits turning a continuous value
into a named regime, choosing a style, handling missing data or acting on an enum.
The first matching arm wins, so write the most specific cases first.

## Produce a value

A match expression gives each case a result:

```flowscope
script "Move regime"

data chart = subscribe(data.ohlcv)

fn describeMove(changePct: float?) -> string {
  return match changePct {
    null => "Waiting for data"
    >= 2.0 => "Strong rise"
    > 0.0 => "Rise"
    <= -2.0 => "Strong fall"
    < 0.0 => "Fall"
    _ => "Flat"
  }
}

state hud = entities.labelPool(max: 1, anchor: anchor.topLeft)

on chart.update {
  let open = chart.open
  let close = chart.close
  let change: float? = open != null && close != null && open > 0.0 ? (close / open - 1.0) * 100.0 : null
  if chart.isLast {
    hud.get("move").set(12.0, 12.0, describeMove(change))
  }
}
```

Relational patterns compare the subject with the value after `<`, `<=`, `>` or `>=`.
Because arms are checked top to bottom, `>= 2.0` comes before `> 0.0`. A match
expression must cover every value; a final `_` is the simplest way.

## Choose a colour

```flowscope
script "Delta colour"

data chart = subscribe(data.ohlcv)

pane deltaPane = pane(title: "Delta", height: 0.25)
plot bars = plot.histogram(title: "Delta", on: deltaPane)

on chart.close {
  let delta = chart.delta()
  let volume = chart.volume
  let share: float? = delta != null && volume != null && volume > 0.0 ? delta / volume : null
  let shade = match share {
    null => color.gray
    >= 0.3 => color.green
    <= -0.3 => color.red
    _ => color.yellow
  }
  bars.plot(delta, color: shade)
}
```

## Match statements

Use the statement form to run actions. For one statement an arm needs no braces:

```flowscope
script "Rising streak"

data chart = subscribe(data.ohlcv)

state risingBars = 0

pane streakPane = pane(title: "Rising streak", height: 0.2)
plot streak = plot.histogram(title: "Bars", on: streakPane)

on chart.close {
  let move = ta.change(chart.close)
  match move {
    null => risingBars = 0
    > 0.0 => risingBars += 1
    _ => risingBars = 0
  }
  streak.plot(float(risingBars))
}
```

A statement match need not cover every value.

## Combine cases

Separate alternatives with `|`:

```flowscope
script "Session of the day"

data chart = subscribe(data.ohlcv)

fn sessionName(hour: int) -> string {
  return match hour {
    0 | 1 | 2 | 3 | 4 | 5 => "Overnight"
    6 | 7 | 8 | 9 | 10 | 11 => "Morning"
    12 | 13 | 14 | 15 | 16 | 17 => "Afternoon"
    _ => "Evening"
  }
}

state hud = entities.labelPool(max: 1, anchor: anchor.bottomLeft)

on chart.update {
  let t = chart.time
  if chart.isLast && t != null {
    hud.get("session").set(12.0, 12.0, sessionName(time.hour(t)))
  }
}
```

Alternatives can mix exact and relational cases: `0.0 | < -3.0 => "Inactive"`.

## Handle missing values first

For a nullable subject, put `null` in its own arm. Exact and relational patterns
never match `null`; only `null` and `_` do.

## Match calculated values

An exact pattern can be a variable or a calculation. The subject is computed once:

```flowscope
script "Session open"

input openHour = input.int(13, title: "Open hour (UTC)", min: 0, max: 23)

data chart = subscribe(data.ohlcv)

pane phasePane = pane(title: "Phase", height: 0.15)
plot phase = plot.histogram(title: "Phase", on: phasePane)

on chart.close {
  let t = chart.time
  if t != null {
    let value = match time.hour(t) {
      openHour => 2.0
      > openHour => 1.0
      _ => 0.0
    }
    phase.plot(value)
  }
}
```

Exact patterns use plain equality, so they suit integers, strings and enums. Compare
prices with relational arms instead.

## What patterns do not do

Patterns compare one subject. They do not bind names, destructure records or take
`if` guards. Read fields into locals first, or compute an extra condition before the
match.

## Match or if?

- A match expression calculates one result from several cases of one value.
- A match statement dispatches actions from one value.
- `if` suits one or two unrelated conditions.
