2. evaltime and runtime
Execution in alv is split into two phases - evaltime and runtime.
At evaltime, that is whenever there is change to the source code, alv
behaves similar to a Lisp. But once one such eval cycle has executed,
runtime starts, and alv behaves like a dataflow system like
PureData, Max/MSP or vvvv.
Every alive expression returns a stream of values. Whenever an input to an
operator changes, the operator (may) update and respond with a change to its
output as well. To see this in action, we need to start with a changing value.
Number literals like 1 and 2, are evaltime constant, which means simply
that they will never update. Since all inputs to our math/+ operator are
evaltime constant, the result is constant as well. To get some runtime
activity, we have to introduce a side-effect input from somewhere outside the
system.
The time module contains a number of operators whose outputs update
over time. Lets take a look at time/tick:
(import* time)
(trace (tick 1))
This will print a series of numbers, incrementing by 1 every second. The
parameter to time/tick controls how quickly it counts - try changing it to
0.5 or 2. As you can see, we can change time/tick while it is
running, but it doesn't lose track of where it was!
All of the other things we learned above apply to streams of values as well -
we can use def to store them in the scope, transform them using the ops
from the math module and so on:
(import* time math)
(def tik (tick 0.25))
(trace (/ tik 4))
Note that if you leave the time/tick's tag in place when you move it into
the def expression, it will keep on running steadily even then.