<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, Apr 21, 2015 at 6:40 PM, davean <span dir="ltr"><<a href="mailto:davean@xkcd.com" target="_blank">davean@xkcd.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr">So, I've had a number of issues with exceptions. This has been one of them. I don't really like this proposal as it stands though as it seems to make catch a specific exception with said extra info more difficult.<div class="gmail_extra"><br></div><div class="gmail_extra">This is data Control.Exception can move around on its own though, right? The problem really isn't passing it internal, we could just make a (Stack, SomeException) tuple just fine, in theory I think (I'll admit I've not actually reviewed the code, and this isn't meant as a complete proposal but more a thought experiment). The problem is code handling the data and working with old code while not losing any of the power of the current system.</div><div class="gmail_extra"><br></div><div class="gmail_extra">So we start with: catch :: Exception e<span style="white-space:pre-wrap"> </span>=> IO a -> (e -> IO a)<span style="white-space:pre-wrap"> </span>-> IO a</div><div class="gmail_extra"><br></div><div class="gmail_extra">Now this proposal allows: catch :: IO a -> (<span style="font-family:arial,helvetica,sans-serif;font-size:12.8000001907349px">SomeException</span> -> IO a)<span style="white-space:pre-wrap"> </span>-> IO a</div><div class="gmail_extra"><div class="gmail_extra"><div>If we want access to the new information, but that's not really satisfactory.<br></div><div><br></div><div>Real code regularly wants to (picking an arbitrary instance of Exception) do: catch :: IO a -> (IOError -> IO a)<span style="white-space:pre-wrap"> </span>-> IO a </div><div>only we still want new data.</div></div></div></div></blockquote><div> </div><div>There is no way to always pass around the new data without breaking the Control.Exception API or having users add extra fields to their data types.  This is a fundamental issue, and one that my proposal does not seek to address.  Infact, I acknowledge it at the end - fromException now loses data.  To me it is quite acceptable because:</div><div><br></div><div>* This is a fundamental limitation of the existing Control.Exception API.  This proposal allows us to gracefully update to a new API which does preserve the new info when catching / rethrowing.</div><div><br></div><div>* These extra annotations are primarily for debugging purposes.  It shouldn't be a correctness issue for them to be lost due to rethrowing something other than SomeException.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra">Now one could do something like: catch :: IO a -> (Stack -> IOError -> IO a)<span style="white-space:pre-wrap"> </span>-> IO a</div><div class="gmail_extra">but that is not very upgradable and it breaks existing code.</div><div class="gmail_extra"><br></div><div class="gmail_extra">But this is just a matter of requesting information, so one could do something like: catch :: IO a -> (WithStack IOError -> IO a)<span style="white-space:pre-wrap"> </span>-> IO a</div><div class="gmail_extra">where: data WithStack e = WithStack Stack e</div><div class="gmail_extra">Or maybe one just addes: catchWithContext :: Exception e => IO a -> (Context -> e -> IO a)<span style="white-space:pre-wrap"> </span>-> IO a</div><div class="gmail_extra">Or: catchWithContext :: Exception => IO a -> (Context e -> IO a)<span style="white-space:pre-wrap"> </span>-> IO a</div><div class="gmail_extra"><br></div><div class="gmail_extra">Now existing code continues to run and we can feed our exception handlers the data they want, even when we want some specific exception instead of just any exception.</div></div></blockquote><div><br></div><div>This is a good idea, which is directly supported by this proposal.  You would simply have the implementation of fromException populate the info in your With* datatype.   Or, the definition I would prefer:</div><div><br></div><div><div><br></div><div>    data WithExceptionInfo e = WithExceptionInfo e [SomeExceptionInfo]</div><div>        deriving Typeable</div><div><br></div><div>    instance Exception e => Exception (WithExceptionInfo e) where</div><div>        fromException (SomeExceptionWithInfo e infos) =</div><div>            fmap (\e' -> WithExceptionInfo e' infos) (cast e)</div><div>        toException (WithExceptionInfo e infos) =</div><div>            SomeExceptionWithInfo e infos<br><br>Does this help clarify my proposal?  As far as I can tell there is no contradiction or difference between our proposals.  I think you would end up with essentially the same thing I have (maybe with different names ;) ), if you tried implementing your ideas in the context of Control.Exception.</div></div><div><br></div></div></div></div>