<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Sep 10, 2018 at 10:48 AM, <a href="mailto:e@bestmx.net">e@bestmx.net</a> <span dir="ltr"><<a href="mailto:e@bestmx.net" target="_blank">e@bestmx.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">i'm sorry to interrupt,<br>
but all you REALLY NEED is to tweak the "try..catch" a little bit,<br>
in a manner that the catch clause receives and returns<br>
more comprehensible values, the values that are clearly linked<br>
with the failed expressions and human readable.<br>
<br>
you do not need a new messy CRYPTIC operator.<br>
<br>
try<br>
  {ok, Result} = foo(...)<br>
, {ok, _} = foo2(...)<br>
catch<br>
 {somehow_identify_which_line_<wbr>failed, unobscured_the_rightside_value<wbr>}<br></blockquote><div><br></div><div>This here is exactly the problem -- you can't somehow identify which line failed unobscured with the right value. First, you need to be able to analyze the stacktrace for that, but there is no mechanism to do so. The new stacktrace syntax specifies that it can't be a pattern match, and the old form requires you to call 'get_stacktrace()' within the clause, which prevents you from doing wide-matches (you'd need a case expression within the catch), and then you'd need to re-throw. This also has a performance cost, but let's assume we could get it for free (this needs new magical syntax as well). Take for example:</div><div><br></div><div><span style="font-family:monospace,monospace">succeeds_n_times(0) -> ok;</span></div><div><span style="font-family:monospace,monospace">succeeds_n_times(N) when N > 0 -></span></div><div><span style="font-family:monospace,monospace">    try <br></span></div><div><span style="font-family:monospace,monospace">        risky_operation(),</span></div><div><span style="font-family:monospace,monospace">        succeeds_n_times(N-1)<br></span></div><div><span style="font-family:monospace,monospace">    catch</span></div><div><span style="font-family:monospace,monospace">        throw:risky_operation_failed:_Stack:{?MODULE, AcceptedLine} -></span></div><div><span style="font-family:monospace,monospace">            {error, risky_operation_failed}<br></span></div><div><span style="font-family:monospace,monospace">    end</span></div></div><div class="gmail_quote"><br></div><div class="gmail_quote">Note that this form breaks tail-recursion. A more proper one would look like:<br><div>
<div><span style="font-family:monospace,monospace"><br></span></div><div><span style="font-family:monospace,monospace">succeeds_n_times(0) -> ok;</span></div><div><span style="font-family:monospace,monospace">succeeds_n_times(N) when N > 0 -></span></div><div><span style="font-family:monospace,monospace">    try risky_operation() of  % we need 'of' to preserve tail-recursion</span></div><div><span style="font-family:monospace,monospace">        ok -> succeeds_n_times(N-1)<br></span></div><div><span style="font-family:monospace,monospace">    catch</span></div><div><span style="font-family:monospace,monospace">        throw:risky_operation_failed:_Stacktrace:{?MODULE, AcceptedLine} -></span></div><div><span style="font-family:monospace,monospace">            {error, risky_operation_failed}<br></span></div><div><span style="font-family:monospace,monospace">    end</span></div>

</div><div><br></div><div>And now it would work. The problem of course is that we don't have an easily spotted exception there. What we can work with if we don't want to annotate all of the calls to risky code is only a badmatch:</div><div><br></div><div>
<div><span style="font-family:monospace,monospace">succeeds_n_times(0) -> ok;</span></div><div><span style="font-family:monospace,monospace">succeeds_n_times(N) when N > 0 -></span></div><div><span style="font-family:monospace,monospace">    try risky_operation() of  % we need 'of' to preserve tail-recursion</span></div><div><span style="font-family:monospace,monospace">        ok -> succeeds_n_times(N-1)<br></span></div><div><span style="font-family:monospace,monospace">    catch</span></div><div><span style="font-family:monospace,monospace">        error:{badmatch, _}:_Stacktrace:{?MODULE, AcceptedLine} -></span></div><div><span style="font-family:monospace,monospace">            {error, risky_operation_failed}<br></span></div><div><span style="font-family:monospace,monospace">    end</span></div>

<br></div><div>so this could work, but only as long as you always have the right module and the right line number. If you don't match this correctly, you may catch failures from other nested calls. The downside is obviously that you don't want to tie your patterns to line numbers, since any change in unrelated code may break all of your error handling. But without line numbers there is no good way to know, from a remote scope, whether you wanted something to match-or-return, or to match-and-abort.</div><div><br></div><div>Even if we had a syntax for the function name as well:</div><div><br></div><div>
<div><span style="font-family:monospace,monospace">succeeds_n_times(0) -> ok;</span></div><div><span style="font-family:monospace,monospace">succeeds_n_times(N) when N > 0 -></span></div><div><span style="font-family:monospace,monospace">    try <br></span></div><div><span style="font-family:monospace,monospace">        ok = risky_operation1(),</span></div><div><span style="font-family:monospace,monospace">        {ok, _} = risky_operation2()</span></div><div><span style="font-family:monospace,monospace">    of<br></span></div><div><span style="font-family:monospace,monospace">        ok -> succeeds_n_times(N-1)<br></span></div><div><span style="font-family:monospace,monospace">    catch</span></div><div><span style="font-family:monospace,monospace">        error:{badmatch, _}:_Stacktrace:{?MODULE, {succeeds_n_times, 1}, _Line} -></span></div><div><span style="font-family:monospace,monospace">            {error, risky_operation_failed}<br></span></div><div><span style="font-family:monospace,monospace">    end</span></div>

<br></div><div>Then you cannot know whether you're capturing risky_operation1 or risky_operation2 without specifying and accounting for all line numbers. This is impractical and brittle. The only way to do this kind of flow safely is with throws identifying every call-site and then we're back to exception-based error handling. Compare with the proposed format:</div><div><br></div><div>
<div><span style="font-family:monospace,monospace">succeeds_n_times(0) -> ok;</span></div><div><span style="font-family:monospace,monospace">succeeds_n_times(N) when N > 0 -></span></div><div><span style="font-family:monospace,monospace">    begin</span></div><div><span style="font-family:monospace,monospace">        _ <~ risky_operation1(), % captured</span></div><div><span style="font-family:monospace,monospace">        {ok, _} = risky_operation2(), % not captured; hard assertion<br></span></div><div><span style="font-family:monospace,monospace">        succeeds_n_times(N-1)<br></span></div><div><span style="font-family:monospace,monospace">    end</span></div>



<br></div><div> This form only captures what it has to capture, and does not have any pitfalls hidden regarding tail recursion.<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
and if (i am ignorant about that) "try" has drawbacks,<br>
then reimplement it the way you intend to implement your new operator.<div class="HOEnZb"><div class="h5"><br></div></div></blockquote><div><br></div><div>That's the thing; there is no way to get a semantically equivalent mechanism with try ... catch without instrumenting the called code rather than just the callers. The easiest semantic comparison is with nested case ... of expressions, not try ... catch. Even if we extended try ... catch to somehow be able to only capture errors in its direct scope, we couldn't easily distinguish between calls we want to fail on a badmatch and those we won't. Line numbers are poor identifiers since they're very easy to change. A line of comments or a re-wrapping of exports could break all error handling in a module.<br></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Sep 10, 2018 at 10:48 AM, <a href="mailto:e@bestmx.net">e@bestmx.net</a> <span dir="ltr"><<a href="mailto:e@bestmx.net" target="_blank">e@bestmx.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">i'm sorry to interrupt,<br>
but all you REALLY NEED is to tweak the "try..catch" a little bit,<br>
in a manner that the catch clause receives and returns<br>
more comprehensible values, the values that are clearly linked<br>
with the failed expressions and human readable.<br>
<br>
you do not need a new messy CRYPTIC operator.<br>
<br>
try<br>
  {ok, Result} = foo(...)<br>
, {ok, _} = foo2(...)<br>
catch<br>
 {somehow_identify_which_line_<wbr>failed, unobscured_the_rightside_value<wbr>}<br>
    ->  ...<br>
  -<br>
    -> default_returnvalue<br>
end<br>
<br>
and if (i am ignorant about that) "try" has drawbacks,<br>
then reimplement it the way you intend to implement your new operator.<div class="HOEnZb"><div class="h5"><br>
<br>
<br>
______________________________<wbr>_________________<br>
eeps mailing list<br>
<a href="mailto:eeps@erlang.org" target="_blank">eeps@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/eeps" rel="noreferrer" target="_blank">http://erlang.org/mailman/list<wbr>info/eeps</a><br>
</div></div></blockquote></div><br></div>