I am reading this blog and came across following code
RunAgain = Class.new(Exception)
def fib(i, n = 1, result = 0)
if i == -1
result
else
raise RunAgain
end
rescue RunAgain
i, n, result = i - 1, n + result, n
retry
end
It seems like for above code to work, once exception is raised then ruby must be clearing the whole stack trace and replacing that with the stack of Exception.
Is my understanding right?
The way this code works actually has nothing to do with the stacktrace. There are two entries on the stack the entire time,
fiband the caller offib. The raise of the exception is sort of a red herring to your question–it doesn’t serve any useful purpose in this example other than as a demonstration of the behavior ofretry.Ruby’s
retryis similar to other control keywords likenextandbreak, andredo. Theredokeyword means to retry the current loop or block from the top. Theretrykeyword works inside a rescue to retry the current block that threw the exception.So what happens here is some initial values are set for
i,n, andresult, a base case is checked (i == -1), and if not satisfied, we update the values and retry from the top. Notice that since these values are method parameters and not local variables, they are not reinitialized.Careful, since Fibonacci is a very common example (and a very poor one) of recursion, not to mistake this for a recursive algorithm. The
RunAgainraise and rescue functions like a loop, without re-calling the function or modifying the callstack.Your example code is equivalent to
Note in both cases,
iis just a counter and nothing more. We run the codei+1times. Note also the typical need for a temporary variable to swap values is replaced by ruby’s multiple assignment construct.