# Recursion

A function may call itself, or form a cycle with other functions.
Recursive types are allowed (`replies: List<Comment>`), and recursion is
the only way to walk them:

```jadpo
function reply_count(comment: Comment) -> ReplyTotal {
    var mut count: ReplyTotal = 0
    for reply in comment.replies {
        count = ReplyTotal(count + 1 + reply_count(reply))
    }
    return count
}
```

Only functions may recurse. An action or query in a cycle of calls is an
error (`effect.recursive_action`).

How deep recursion can go is limited while the app runs, and going past
the limit ends in a defined fault rather than a crash. The limits are the
same in the interpreter and in a compiled build, on every target:

- **A thousand frames**, the test's own or the route's action's among them.
- **Four hundred inline functions running at once**, one inside another's
  body through the functions it calls.

Past either, the call or operation that would go deeper is the
`recursion_limit` fault, at its place in the code. That holds in
`jadpo test` and `jadpo dev` as in a deployable, a compiled build of your
app. So `reply_count` above walks a thread a thousand replies deep, and
the same walk written as `list.map(comment.replies, reply -> ...)` four
hundred.

Inline functions have the lower limit because compiled code runs each one
inside its operation, several of the runtime's frames deep. On Workers
those frames use V8's own stack, about a megabyte that nothing in the
module can grow.

The stacks behind the limits:

- A native deployable's threads have the same stack as `jadpo test`'s,
  64 MiB.
- A Workers module is linked with 8 MiB of its own stack, which a thousand
  frames of a large function fit. In a module, a callable entered with less
  than 256 KiB of it left is also the `recursion_limit` fault, so an even
  larger frame stops there rather than writing past the stack's end.
