millionchart
فارسی

let, mut and state

The three kinds of name and the run model behind them. A value that never changes, one that is set again on every bar, and one that is kept.

To read a script you need one fact: the whole file runs again for every bar, from the top to the bottom. A name that is created inside the file is created again on every bar. The three words let, mut and state say what happens to a name from one bar to the next.

The run model#

On bar 1 the script runs from its first line to its last, then on bar 2 from its first line to its last, and so on to the newest bar. Everything the script computes on a bar is thrown away when the bar ends, except what you ask it to keep.

WordMeaning
letA value that is set once on each run and never changes during it.
mutA value that starts again on each run and may be given a new value during it.
stateA value that is set the first time the script runs and kept from one bar to the next.
Cuprel
indicator "Three kinds of name"
    edition = 1

state kept = 0
mut capped = high - low
let body = close - open
kept += 1
if capped > 10
    capped = 10
plot(kept, name = "state: counts the bars")
plot(capped, name = "mut: this bar's range, at most 10")
plot(body, name = "let: this bar's body", style = histogram)

Only the state line remembers anything. On the 500th bar kept is 500; capped and body are made again from that bar's prices.

Cuprel · warning W-MUT-COUNTER
indicator "A counter that restarts"
    edition = 1

mut count = 0
count += 1
plot(count)

If you want it kept, say state. If you really want to build on the last bar's final value, read it with [1]:

Cuprel
indicator "Running total from the bar before"
    edition = 1

mut total = 0.0
total = (total[1] ?? 0) + (close - open)
plot(total, name = "Running total of bar bodies")

total[1] is the value total ended with on the bar before; ?? 0 turns the empty first value into 0.

let does not change#

Giving a new value to a let name is an error. The message says what to write:

Cuprel · error E3103
indicator "Changing a let"
    edition = 1

let total = 0
total += 1
plot(total)

Writing a name you never declared is an error as well (E3102): declare it with let, mut or state first. Declaring the same name twice in one place is E3101. These checks catch the commonest slip, which is a typing mistake that would otherwise create a second variable and leave the first one unchanged.

No hidden copies#

An assignment never creates a new name. A line such as x = 5, even deep inside an if, changes the x you declared with mut or state; if there is none, it is an error. A name inside a function that has the same name as one outside it is allowed but warned about (W-SHADOW-GLOBAL), because it is almost always a mistake.

A function may not change a mut or state name declared outside it. Pass a value in and return one out:

Cuprel · error E3104
indicator "A function that writes outside"
    edition = 1

state hits: int = 0
fn count_up(): int
    hits += 1
    return hits
plot(count_up())

Stateful calls belong at the top#

Functions such as tech.ema, tech.crosses_above and tech.rsi keep a memory from bar to bar. Each place in the script where you call one has its own memory, and it can only remember the bars on which that call ran. So call them at the top of the script, on every bar, and put the if around what you do with the answer. If you call one inside an if, it only sees the bars the if was true on:

Cuprel · warning W3302
indicator "Same call, two places"
    edition = 1

let always = tech.ema(close, 10)
mut sometimes = na
if bar.index % 3 == 0
    sometimes = tech.ema(close, 10)
plot(always, name = "On every bar")
plot(sometimes, name = "Only on every third bar")

The second line is not the same average thinned out: it is an average of every third bar, and the checker says so with the warning W3302. A call that keeps state inside a loop is refused (E3301), for the same reason; see Choices and loops.

A kept value that starts again#

state can restart on a schedule. state day starts again on the first run in each trading day, and state session on each run of a session. They are covered with sessions in Trading day and sessions.

See also: Values and types, Functions, types and enums, Common mistakes.