Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to cast exceptions thrown via `throwTo` using `fromException`

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.

like image 956
nek0 Avatar asked Oct 23 '25 06:10

nek0


1 Answers

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.

like image 106
snak Avatar answered Oct 26 '25 05:10

snak