<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Jul 11, 2013 at 3:44 AM, John Lato <span dir="ltr">&lt;<a href="mailto:jwlato@gmail.com" target="_blank">jwlato@gmail.com</a>&gt;</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">Hi Michael,<div><br></div><div>I don&#39;t think those are particularly niche cases, but I still think this is a bad approach to solving the problem.  My reply to Erik explicitly covers the worker thread case, and for running arbitrary user code (as in your top line) it&#39;s even simpler: just fork a new thread for the user code.  You can use the async package or similar to wrap this, so it doesn&#39;t even add any LOCs.</div>




<div><br></div><div>What I think is particularly niche is not being able to afford the cost of another fork, but I strongly doubt that&#39;s the case for Warp.</div><div><br></div><div>The reason I think this is a bad design is twofold: first maintaining a list of exclusions like this (whether it&#39;s consolidated in a function or part of the exception instance) seems rather error-prone and increases the maintenance burden for very little benefit IMHO.</div>




<div><br></div><div>Besides, it&#39;s still not correct.  What if you&#39;re running arbitrary user code that forks its own threads?  Then that code&#39;s main thread could get a BlockedIndefinitelyOnMVar exception that really shouldn&#39;t escape the user code, but with this approach it&#39;ll kill your worker thread anyway.  Or even malicious/brain-damaged code that does myThreadId &gt;&gt;= killThread?</div>




<div><br></div><div>I like Ertugrul&#39;s suggestion though.  It wouldn&#39;t fix this issue, but it would add a lot more flexibility to exceptions.<br></div></div><div><div><div class="gmail_extra">
<br><br></div></div></div></blockquote><div><br></div><div>I&#39;ve spent some time thinking about this, and I&#39;m beginning to think the separate thread approach is in fact the right way to solve this. I think there&#39;s really an important distinction to be made that we&#39;ve all gotten close to, but not specifically identified: the exception type itself isn&#39;t really what we&#39;re interested, it&#39;s how that exception was thrown which is interesting. I&#39;ve put together an interesting demonstration[1].</div>

<div><br></div><div>The test I&#39;ve created is that a worker thread is spawned. In the worker thread, we run an action and wrap it in a &quot;tryAll&quot; function. Meanwhile, in the main thread, we try to read a file and, when it fails, throw that IOException to the worker thread. In this case, we want the worker thread to halt execution immediately. With the naive try implementation (tryAll1) this will clearly not happen, since the async exception will be caught as if the subaction itself threw the exception. The more intelligent tryAll3 does the same thing, since it is viewing the thrown exception as synchronous based on its type, when in reality it was thrown as an async exception.[2] The only approach that handles the situation correctly is John&#39;s separate thread approach (tryAll3). The reason is that it is properly differentiating based on how the exception was thrown.</div>

<div><br></div><div>I&#39;m going to play around with this a bit more; in particular, I want to see how this works with monad transformer stacks. But I at least feel like I have a slightly better conceptual grasp on what&#39;s going on here. Thanks for pointing this out John.</div>

<div><br></div><div>Michael</div><div><br></div><div>[1] <a href="https://gist.github.com/snoyberg/5975592">https://gist.github.com/snoyberg/5975592</a></div><div>[2] You could also do the reverse: thrown an async exception synchronously, and similarly get misleading results.</div>



</div></div></div>