--- layout: developer-doc title: Managed Resources category: semantics tags: [resources, finalization, cleanup] order: 10 --- # Tail Call Optimization Tail call optimization is a powerful technique for optimizing functional programs. It allows transforming recursive functions of certain shapes into loops, removing unnecessary intermediate function calls and saving stack space. This document outlines the usage and semantics of tail call optimization in Enso. - [Tail Calls](#tail-calls) - [Usage](#usage) ## Tail Calls A Tail Call is a function call occurring as the last statement in a function body, i.e. an expression whose value is guaranteed not to be depended upon by the function itself. For example, ```hs sum_1 n = if n == 0 then 0 else 1 + sum_1 n-1 sum_2 n acc = if n == 0 then acc else @Tail_Call sum_2 n-1 acc+n ``` In the code snippet above, only the `sum_2` function is tail recursive. The result of calling `sum_2` recursively is not depended upon by `sum_2` itself or the definition of `if_then_else` method on booleans. On the other hand, `sum_1` needs to know the value of its recursive call in order to perform the addition operation. It is advised that functions that can be expressed with tail-calls are implemented that way. Using tail call optimization, will lead to `sum_2` being orders of magnitude faster than `sum_1`. Moreover, for `n = 100000000`, `sum_1` will allocate a hundred million stack frames (over a gigabyte, likely resulting in a stack overflow error), while `sum_2` is an allocation-free loop. ## Usage Enso does not currently perform automatic tail call detection and defers the optimization decisions to the user. To mark a function call as a tail call, the `@Tail_Call` annotation must be used. Note that if the annotation is placed incorrectly, it may either be reported as a warning by the compiler, or silently ignored if such analysis is impossible to perform due to the compiler's limited static analysis capabilities. However, it is _guaranteed_ that a wrongly placed `@Tail_Call` annotation will not lead to incorrect runtime behavior. If the `@Tail_Call` annotation is not placed, the call will be treated as a standard on-stack function call. For example, the following code reverses a list in a tail recursive fashion: ``` reverse list = go list result = case list of Nil -> result Cons head tail -> @Tail_Call go tail (Cons head result) result = go list Nil result ``` Note the placement of `@Tail_Call` in the recursive branch of `go`. It is placed correctly, marking the last operation in a function, and therefore `go` will be interpreted as a loop rather than a chain of function calls. > #### Debugging Tail Calls > > The way `go` is wrapped in the example above is recommended for most uses. > Using the assignment and return of a variable, rather than a direct call, > guarantees that calls to `reverse` won't themselves be removed from the call > stack and therefore greatly aids debugging.