While working on a Haskell project I encounter the problem, that any exception thrown to a thread via throwTo results in a Nothing when casted from the SomeException type back into my own exception type using fromException. As a demonstration, consider this code snippet:
{-# LANGUAGE LambdaCase #-}
import Control.Concurrent (threadDelay)
import UnliftIO.Async (async, asyncThreadId, waitCatch)
import UnliftIO.Exception (Exception, SomeAsyncException (..), SomeException (..),
asyncExceptionToException, catch, fromException, throwIO,
throwTo, toException)
data MyException = Type1 | Type2
deriving (Show)
instance Exception MyException
toMyException :: SomeException -> Maybe MyException
toMyException = fromException
sleepAndThrow :: (Exception e) => Int -> e -> IO ()
sleepAndThrow i e = do
threadDelay (i * 1000000)
print e
throwIO e
main :: IO ()
main = do
t1 <- async $ sleepAndThrow 1 Type1 -- Throw Type1 in 1 second
t2 <- async $ threadDelay 500000 >> throwTo (asyncThreadId t1) Type2 -- Cancel t1 in 0.5
-- seconds with Type2
waitCatch t1 >>= \case
Left e -> putStr "Exception: " >> print (toMyException e)
Right () -> error "this should not happen"
Looking at this, I would expect the following console output:
Exception: Just Type2
Whereas I get a:
Exception: Nothing
Can anyone of you please show me, what I'm doing wrong?
Thanks in advance.
Make your exception an async exception if you're going to throw it asynchronously.
instance Exception MyException where
toException = asyncExceptionToException
fromException = asyncExceptionFromException
This means that you need to have two distinct types for Type1 and Type2 if you're going to throw Type1 synchronously and Type2 asynchronously.
But in general, I'd recommend not to use asynchronous exceptions directly, but use utilities in async package such as race.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With