Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No tail recursive code in a try catch block?

Tags:

erlang

I am reading the Erlang lesson at http://learnyousomeerlang.com/errors-and-exceptions

I don't understand this part :

The Expression in between try and of is said to be protected. This means that any kind of exception happening within that call will be caught.

And

the protected part of an exception can't be tail recursive.

[...]

By putting your recursive calls between the of and catch, you are not in a protected part and you will benefit from Last Call Optimisation.

So we can't put recursive calls in the part where the exceptions are catched ? What's the point of the try catch block then ?

And below in the page we have an example with a tail recursive function in the protected section ...

has_value(Val, Tree) ->
  try has_value1(Val, Tree) of
    false -> false
  catch
    true -> true
  end.

has_value1(_, {node, 'nil'}) ->
  false;
has_value1(Val, {node, {_, Val, _, _}}) ->
  throw(true);
has_value1(Val, {node, {_, _, Left, Right}}) ->
  has_value1(Val, Left),
  has_value1(Val, Right).

Does he mean that we need to use a function to wrap tail recursive code into a function when we are in the protected part of a try catch ?

like image 254
Simon Avatar asked Jul 09 '13 23:07

Simon


1 Answers

So we can't put recursive calls in the part where the exceptions are catched ? What's the point of the try catch block then ?

A function cannot recursively call itself inside of a try; or rather, tail optimization will not happen if it does. When you use try, you have to be able to jump back to the catch block at any point down the call stack. What that means is that there has to be a call stack. If tail call optimization is used, there are no function calls because they're just loops now. There's nothing to jump back to. Thus recursion inside of a try block must truly recurse.

The point is the same as exceptions in most languages. The fact that you cannot directly recurse is a bit of an annoyance, but certainly does not remove the utility of exception handling, because:

Does he mean that we need to use a function to wrap tail recursive code into a function when we are in the protected part of a try catch ?

Yes. All it takes is one extra function and you can use try just fine, and still gain the benefits of TCO. Example:

% No TCO
func() ->
  try
    func()
  catch _ ->
    ok
  end.

% TCO
func() ->
  try
    helper()
  catch _ ->
    ok
  end.

helper() -> helper().

I'm not sure if there's an easy way to determine if you're accidentally recursing when you expect TCO to happen. You probably just have to be vigilant when using try.

like image 194
Chris Avatar answered Sep 17 '22 18:09

Chris