No tail recursive code in try catch block?

I read Erlang's lesson http://learnyousomeerlang.com/errors-and-exceptions

I do not understand this part:

The expression between try and to is considered protected. This means that any exception occurring in this call will be caught.

and

the protected part of the exception cannot be tail recursive.

[...]

By placing your recursive calls between "and" and "catch", you are not in the protected part, and you will benefit from the optimization of recent calls.

So we cannot put recursive calls in the part where the exceptions are caught? What is the point in the try catch block then?

And below on the page we have an example with a tail recursive function in a 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 transfer tail recursive code to a function when we are in the protected part of a try catch?

+7
erlang
source share
2 answers

Thus, we cannot introduce recursive calls to the part where the exceptions are caught? What is the point in the try catch block then?

A function cannot recursively call itself inside try ; or rather, tail optimization will not happen if it does. When you use try , you should be able to return to the catch at any point in the call stack. This means that there must be a call stack. If tail call optimization is used, there are no function calls because they are now just loops. There is nothing to return. Thus, the recursion inside the try block should really return.

The dot matches exceptions in most languages. The fact that you cannot directly recurs is a bit annoying, but, of course, does not remove the exception handling utility, because:

He means that we need to use a function to wrap the tail recursive code in a function when we are in the protected part of try catch

Yes. All that is required is one additional feature, and you can use try just fine and still enjoy 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 is an easy way to determine if you accidentally return when you expect TCO to happen. You probably just need to be vigilant when using try .

+11
source share

If you want to optimize the callback, this call must be outside the try-catching clause. You can use the construct

 your_fun(...) -> ... try ... of <--- make notice of `of` ... -> some_call(...) catch ... end. 

or just make this call after a try clause.

In your code that calls has_value1(Val, Right). , optimized because this is the last function call. It does not matter if it is called inside a try block in this case. An exception is used only to provide an early exit from this function and to easily manage the result.

It can be rewritten without exception, but using manual stack processing:

 has_value(Val, Tree) -> has_value(Val, [Tree]). has_value1(_, []) -> false; has_value1(Val, [{node, 'nil'} | Stack]) -> has_value1(Val, Stack); has_value1(Val, [{node, {_, Val, _, _}} | _]) -> true; has_value1(Val, [{node, {_, _, Left, Right}} | Stack]) -> has_value1(Val, [Left, Right | Stack]). 
0
source share

All Articles