As far as I understand it, besides lacking the alloc_locals
step, tempvar
is mainly useful for exactly what it says: temporary variables. Think counters in a loop, or accumulators. These variables not only change during the same function call, but they change a number of times that is not statically known, prohibiting us from just using alloc_locals
to allocate space relative to fp
.
Take the following loop as an example. We’re leveraging that, unlike fp
, we can advance ap
during a call, and give names to things at a specific offset from ap
, so that while memory is immutable, we can still change what “the value 2 cells before where ap
is pointing” is by advancing ap
and specifying that value.
func sum_tempvar(arr_len : felt, arr : felt*) -> (res : felt):
tempvar acc = 0
tempvar arr = arr
tempvar arr_len = arr_len
loop:
if arr_len == 0:
return (acc)
end
tempvar acc = acc + [arr]
tempvar arr = arr + 1
tempvar arr_len = arr_len - 1
jmp loop
end
The alternative without tempvar
would be to use recursion, e.g.
func sum(arr_len : felt, arr : felt*) -> (res : felt):
let (res) = sum_rec(arr_len, arr, 0)
return (res)
end
func sum_rec(arr_len : felt, arr : felt*, acc : felt) -> (res : felt):
if arr_len == 0:
return (acc)
end
return sum_rec(arr_len - 1, arr + 1, acc + [arr])
end
This does the same sort of thing but instead by advancing fp
using a function call, it comes with overhead though from setting up the call, proportional to the number of iterations, and if there were any constants (w.r.t to the recursive calls) that were not statically known (e.g. parameters in some model), I believe you would have to pay an additional cost for either copying them, or pointing to some struct/tuple of said constants. Whether or not this matters depends on context.