[erlang-questions] tail recursion : sharing a learning and a question
Amit Murthy
amit.murthy@REDACTED
Mon Aug 17 20:13:49 CEST 2009
Thanks Richard. A pretty neat solution and a very clear explanation.
Amit
On Mon, Aug 17, 2009 at 10:12 PM, Richard Carlsson <richardc@REDACTED>wrote:
> Amit Murthy wrote:
>
>> I just learned that every iteration of the below code goes onto the stack.
>> The evaluation of the "catch" has something to do with it
>>
>> do_maintenance(CacheSz, HKIntvl, Oldest) ->
>> try
>> receive
>> ...
>> after HKIntvl ->
>> ...
>> do_maintenance(CacheSz, HKIntvl, NOldest)
>> end
>> catch
>> error:Error ->
>> ...
>> do_maintenance(CacheSz, HKIntvl, Oldest)
>> end.
>>
>> The right way of course is to not trap exceptions here, remove the
>> try-catch
>> and put the whole thing under a supervisor (with restart) behavior.
>> Which is what I have done now.
>>
>
> It would be sufficient to rewrite it like this:
>
> do_maintenance(CacheSz, HKIntvl, Oldest) ->
> try
> receive
> ...,
> Oldest
> after HKIntvl ->
> ...,
> NOldest
> end
> of
> NewOldest -> do_maintenance(CacheSz, HKIntvl, NewOldest)
> catch
> error:Error ->
> ...
> do_maintenance(CacheSz, HKIntvl, Oldest)
> end.
>
> The "protected" part of the code is the one between 'try' and 'of',
> or between 'try' and 'catch' if there is no 'of' section. In the
> protected part, tail recursive calls are not possible. (The call
> in the 'catch...end' section, however, is tail recursive here.)
>
> Basically, what your version of the code says is "if the recursive
> call fails, we must catch that before we are allowed to exit from
> the current call". The rewritten version above says "do the receive
> and the log_info or cleanup, and catch any errors in that part (but
> only in that part), then do a tail call to exit from the current call".
>
> Would still like to know as to why the try-catch ends up killing tail
>> recursion. Can't the compiler catch this (pun intended) and optimize it
>> for
>> tail recursion?
>>
>
> No, because what the code says is that it should catch errors that may
> happen in the recursive call, and handle the errors using the context of
> the current call (e.g., the current value of Oldest). This means that
> the compiler must keep the stack entry for the current call until the
> recursive call has finished. Hence, no tail recursion optimization.
>
> /Richard
>
More information about the erlang-questions
mailing list