Ruby, of course, has recursion, like any other high-level programming language. This works fine until the recursion depth is too high, but if so, you will catch the stack overflow:
#!/usr/bin/ruby2.0 def rec_naive(i) return 1 if i==1 rec_naive(i-1) + i end puts rec_naive(10000) #(Stack size: ~9360) #==> test.rb:3: stack level too deep (SystemStackError)
The most obvious solution that comes to mind is simply to increase the size of the stack. Unfortunately, the answers that I found on the topic are suggested by changing the state of the OS in one way or another - redoing the source code of the Ruby interpreter, ulimit , compiling flags, etc., which is pure Ruby and, of course, is not always possible, especially in protected environments . Thus, the less obvious solutions that come to mind are to rewrite the violation function in a non-recursive way or override the calling stack:
# Recursion-free way def rec_norecurse(i) acc = 0 (1..i).each do |n| acc += n end return acc end puts rec_norecurse(100) # Reimplementing the call stack StackFrame = Struct.new(:state, :args) def rec_customstack(stack) lastresult = nil until stack.empty? frame = stack.last state, args = frame.state, frame.args i = args[0] case state when :entrance_point if i==1 #-- return 1 #-- lastresult = 1 stack.pop #--------------- else #-- rec(i-1) #-- stack.last.state = :returned_from_recursion stack << StackFrame.new(:entrance_point, [i-1]) #--------------- end when :returned_from_recursion #-- return rec_result+i #-- lastresult = lastresult + i stack.pop #-------------------------- end end return lastresult end customstack = [StackFrame.new(:entrance_point, [100])] puts rec_customstack(customstack)
However, rewriting even less complex functions in this way can be a tedious task, and the resulting code seems too cluttered and obscured compared to the original. I wanted to use some metaprogramming and write some kind of βwrapperβ that could make the wrapped function behave correctly with deep recursion, being clean enough even if it didn't look exactly like it was unfolding. I implemented a solution with Fibers, which initially seemed pretty good, but then I ran into some unexpected difficulties ( see Related question for details).
So, I'm looking for the right and clean - with as little clutter and shadowing as possible - a way to realize very deep recursive calls without damaging the performance too much.