2. evaltime and runtime

So far, alv may seem a lot like any other programming language - you write some code, save the file, and it runs, printing some output. “What about the ‘continuously running’ aspect from the introduction?”, you may ask yourself.

So far, we have only seen evaltime execution in alv - but there is also runtime behavior. At evaltime, that is whenever there is change to the source code, alv behaves similar to a Lisp. This is the part we have seen so far. But once one such eval cycle has executed, runtime starts, and alv behaves like a dataflow system like PureData, Max/MSP or vvvv.

What looked so far like static constants are actually streams 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, which we used so far, 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.