Stateful Variables
How to persist values across executions using Arc's stateful variables
Arc functions execute repeatedly in response to incoming data. Each execution starts fresh, with local variables reset to their initial values. Stateful variables let you preserve values across these executions.
Local vs Stateful Variables
Use := for local variables that reset each execution, and $= for stateful variables
that persist:
func example() {
local := 0 // resets to 0 every execution
state $= 0 // persists across executions
local = local + 1 // always becomes 1
state = state + 1 // increments: 1, 2, 3, ...
} The $= operator declares a stateful variable with an initial value. After the first
execution, subsequent executions use the persisted value instead of the initial value.
Common Patterns
Counter
Track how many times a condition has occurred:
func count_events{threshold f64} (value f64) i64 {
count $= 0
if value > threshold {
count = count + 1
}
return count
} Accumulator
Sum values over time:
func accumulate(value f64) f64 {
total $= 0.0
total = total + value
return total
} Previous Value
Compare the current value to the previous one:
func rate_of_change(value f64) f64 {
prev $= 0.0
delta := value - prev
prev = value
return delta
} Running Maximum
Track the highest value seen:
func running_max(value f64) f64 {
max $= 0.0
if value > max {
max = value
}
return max
} State Toggle
Maintain an on/off state:
func toggle(trigger u8) u8 {
state $= 0
if trigger {
if state == 0 {
state = 1
} else {
state = 0
}
}
return state
} Stateful Variables Replace Loops
Since Arc doesn’t have loops, stateful variables are how you implement iterative algorithms. Instead of looping until a condition is met, you update state each execution and let the reactive model handle the iteration.
Traditional approach (not Arc):
total = 0
for reading in readings:
total += reading
average = total / len(readings) Arc approach:
func running_average(value f64) f64 {
total $= 0.0
count $= 0
total = total + value
count = count + 1
return total / f64(count)
} The function executes once per incoming value, accumulating the total and count across executions.
Reset on Stage Re-entry
When a stage in a sequence is re-entered, all stateful variables in that stage reset to their initial values. This ensures stages start fresh when you transition back to them.
sequence main {
stage monitoring {
// count resets to 0 each time we enter monitoring
sensor -> count_events{threshold=100.0} -> event_count
event_count > 10 => alert
}
stage alert {
// handle alert...
acknowledged => monitoring // re-entering resets count
}
} If you need to preserve state across stage re-entries, put the stateful logic in a function that’s called from the top level (outside any sequence).
Type Inference
Stateful variables infer their type from the initial value, just like local variables. You can also specify the type explicitly:
func example() {
// Type inferred from initial value
count $= 0 // i64 (integer literal default)
total $= 0.0 // f64 (float literal default)
// Explicit type annotation
precise f32 $= 0.0 // f32 instead of f64
} Integer literals default to i64 and float literals default to f64. If you need a
different type, add an explicit annotation.