<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">On Mon, May 16, 2016 at 12:19 PM, Björn Gustavsson <span dir="ltr"><<a href="mailto:bjorn@erlang.org" target="_blank">bjorn@erlang.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div id=":kl" class="">erlang:raise/3 is particularly useful when you<br>
don't want to handle the error, but let you log<br>
important information about the context.</div></blockquote></div><br>I think this is the key insight.</div><div class="gmail_extra"><br></div><div class="gmail_extra">The problem is that in Erlang, an exception is not a first class value. When an exception occurs, it either crashes the process, or it is caught by a "catch-style" expression. When caught, the exception is turned into two atoms, Class and Reason, and as a side-effect the VM tracks the last stacktrace. But an exception is not a first class value, as is the case in e.g., Standard ML.</div><div class="gmail_extra"><br></div><div class="gmail_extra">When the exception is caught, the VM "reflects" the exception into {Class, Reason, erlang:get_stacktrace()} which is now our representation of the exception in our code (since we have no access to first-class exceptions). The erlang:raise/3 function acts as a "reifier" and turns our "proxy-representation" back into a VM exception which the VM can work with.</div><div class="gmail_extra"><br></div><div class="gmail_extra">Any solution not involving exceptions will have to simulate them. The two obvious ways are the process dictionary to track the state of "done" on the socket, or a separate process for either the Fun or the Socket. Neither of these sound desirable to me.</div><div class="gmail_extra"><br></div><div class="gmail_extra">In Standard ML, we can write:</div><div class="gmail_extra"><br></div><div class="gmail_extra"><div class="gmail_extra">datatype ('a, 'b) result = Ok of 'a | Error of 'b</div><div class="gmail_extra"><br></div><div class="gmail_extra">exception Argh of string</div><div class="gmail_extra"><br></div><div class="gmail_extra">fun f () = raise (Argh "Some error here")</div><div class="gmail_extra"><br></div><div class="gmail_extra">fun g () =</div><div class="gmail_extra">   Ok (f ()) handle Ex => Error Ex</div><div class="gmail_extra">   </div><div class="gmail_extra">fun h () =</div><div class="gmail_extra">   case g () of</div><div class="gmail_extra">       Ok v => v</div><div class="gmail_extra">     | Error ex => raise ex</div><div><br></div><div>Note how the function 'g' handles any exception and turns it into an error (wrapped in the a result datatype to make the type system happy). Finally the function 'h' can re-raise the exception in another context:</div><div><br></div><div><div>> use "z.sml";</div><div>exception Argh of string</div><div>val f = fn: unit -> 'a</div><div>val g = fn: unit -> ('a, exn) result</div><div>val h = fn: unit -> 'a</div><div>datatype ('a, 'b) result = Error of 'b | Ok of 'a</div><div>val it = (): unit</div><div>> h ();</div><div>poly: : warning: The type of (it) contains a free type variable. Setting it to a unique</div><div>   monotype.</div><div>Exception- Argh "Some error here" raised</div></div><div><br></div><div><br></div>-- <br><div class="gmail_signature">J.</div>
</div></div>