|
After 20 years of software development in a variety of languages and projects, I've come to the opinion that recursion really should be relegated to being a novelty. Few languages offer tail-call optimization. If we look at popularity of languages, then the likelihood any particular solution is going to end up in such a language is vanishingly small. For the remaining languages, fitting into the stack depth is easy to get wrong. It's easy to end up in an infinite loop that ends in an obscure error with a confusing, verbose, needle-in-hay-stack stack frame that over complicates debugging. And frankly, lots of programmers don't have a good handle on it, even the ones who studied CS in college, so asking them to maintain recursive code written by someone else usually ends pretty poorly. So when we consider that, actually, no, it's not true that using an explicit stack takes "a lot more code" (it's like, three extra lines), recursion starts to look more and more like a code smell, a smell indicating the originating programmer is more a temporarily-embarrassed mathematician than an engineer. To be clear, I have no problems conceiving of and implementing recursive solutions to problems. But every single one of my recursive solutions has eventually failed to survive contact with real life data. It might be next week when the code goes to production or it might be a year from now when the data processing needs grow, but I've eventually replaced them all. I'm not the only one with this opinion. Many safety regulations covering vehicles from cars to spacecraft explicitly ban recursion because of these issues. We need to just stop with the fetishising of math in software development. |
In Racket you can't get a stack overflow.
At the time a potential stack overflow is detected, the oldest parts of the current stack is copied to the heap and a fresh stack is introduced. When the stack underflows the saved stack is reinstated. [At least this is a rough idea of how it works - implementation details differ to make it process efficient.]
This means that you can rely on recursive solutions even when the recursive call occurs in a non-tail context.
This idea (no stack overflows) could be used in more traditional languages too. As you write in traditional languages there is a real risk to bump into the stack limit.