|
|
|
|
|
by anewvillager
2237 days ago
|
|
A (non-tail) recursive function actually needs a reentrant mechanism to implement the semantics of calling itself; this mechanism is a stack. Without recursive functions, we have a bounded call depth and thus don't actually need a growable stack; a fixed-size array suffices. We take for granted that function calls are always implemented with a stack, because that's how processors work today, but it could have been done differently. We could imagine an alternative timeline with much restricted functions and no implicit call stack. And indeed, tail recursive functions are usually implemented with tail call elimination, in which the caller reuses the stack frame of the callee; function call becomes a simple goto, which transforms recursion into loop iteration. If we didn't have an implicit stack we could still have tail recursive functions (and a bounded number of non-tail calls), and manage other recursion cases with explicit stacks. See for example pratt parsing https://matklad.github.io/2020/04/13/simple-but-powerful-pra... which uses the implicit call stack, and contrast with Dijkstra's shunting yard algorithm https://matklad.github.io/2020/04/15/from-pratt-to-dijkstra.... which is the same thing but with an explicit stack. If we didn't have a call stack, we could always program in Dijkstra's style and be none the wiser. |
|