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 ?
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With