<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">2016-12-06 10:25 GMT+01:00 zxq9 <span dir="ltr"><<a href="mailto:zxq9@zxq9.com" target="_blank">zxq9@zxq9.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="gmail-">On 2016年12月6日 火曜日 10:13:34 Dmytro Lytovchenko wrote:<br>
> For things like web form or input validation and transformation, it is<br>
> often a good idea to make a chain of nested calls.<br>
><br>
> Imagine your user submitted a form which you store in Data = #{login="",<br>
> password=""}, you can do something like this:<br>
><br>
> try<br>
>     create_session(check_password(<wbr>check_login(Data)))<br>
> catch throw:{validation_error, E} -> my_report_error(E)<br>
> end,...<br>
><br>
><br>
> Here each function (check_login, check_password, create_session) takes<br>
> result of the previous function, it can be that same Data, or Data paired<br>
> with some intermediate results if you wish. To signal an error you use<br>
> erlang:throw({validation_<wbr>error, "my error"}) and it will be caught in the<br>
> catch clause.<br>
<br>
</span>That's one way to do it... but most code I've seen that makes heavy use<br>
of `throw` has insane structural issues (either actual bugs, or mental<br>
grenades with C++ style confusing execution).<br>
<br>
Basically, what I'm getting at is that `throw` is a keyword oft used in<br>
prayer and curse in Mordor.<br></blockquote><div><br>Any best practice can be corrupted and written in a horrible way, it's a matter of self discipline and good reviewing in the team. Best idea is to not allow throw propagate more than 1 logical level up. We chain-call the handlers, and the handlers are allowed to throw, we catch it. Anything that handlers can call and that can throw, should be caught by them and not propagate wildly onto higher levels.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
Why not return `{error, Reason}` back up the chain of calls? Then the<br>
top-level caller can choose whether to crash on an `{ok, Value}` or<br>
`{error, Reason}` assertion match, or engage in their own insanity with<br>
`throw` .. `catch` and other nonsense
</blockquote><div> </div><div>Absolutely it can be done Haskell/ML way with values wrapped as {ok,_} or {error, _} and returned. This will make beautiful flow and will triple the chain runner function size, or you will have to add an {error, _} clause to each of your handlers. And exceptions still are going to happen, so those have to be caught and wrapped with {error, _} too.<br><br></div><div>On the other hand throw was designed as a way for user to safely interrupt whatever was running and hop out of deep nested calls. Using it wisely and keeping it simple may produce clean short code.<br><br>For simplicity i kept my example short.<br></div><br></div><br></div></div>