I can often make a terminal recursive version of my functions with a little less elegant code. Should I do it because it could reduce the fees or should I keep the unoptimised version?
For example, here is an "unoptimised" function which sums elements of an array:
@view
func get_convoy_strength{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
convoy_id : felt
) -> (strength : felt):
alloc_locals
let (convoyables_len : felt, convoyables : felt*) = get_convoyables(convoy_id)
return _get_convoyables_strength(convoyables_len, convoyables)
end
and here is the tail call optimization:
func _get_convoyables_strength_tc{
syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr
}(convoyables_len : felt, convoyables : felt*, sum : felt) -> (strength : felt):
if convoyables_len == 0:
return (sum)
else:
let convoyable_id = [convoyables]
alloc_locals
let (convoyable_strength) = _get_strength(convoyable_id)
return _get_convoyables_strength_tc(
convoyables_len - 1, convoyables + 1, sum + convoyable_strength
)
end
end
As you can see it's a little less friendly because it requires an additional argument (which will always be 0). On a normal computer this could be optimized to not fill the call stack but as FeedTheFed pointed out, the memory is immutable here so it doesn't seem to be useful. He did say, however, that it could be interesting for "not wasting memory cells for the intermediate return values". It would be very helpful to me to have a more detailed explanation as I'm not sure to understand.
Here is the cairo doc related to this: https://www.cairo-lang.org/docs/how_cairo_works/functions.html?highlight=tail#tail-recursion