Joe Hillenbrand
Joe Hillenbrand

Reputation: 875

try won't handle any exceptions

This is based on the suggestion from my earlier question here:

    go bs = do
       r <- try $ parseRequest reader bs secure
       case r of
         Left ex -> do
            putStrLn "got exception"
            exceptionHandler writer ex
            go empty
         Right (request, bs') -> do
            sendResponse writer =<< app request
            go bs'

When there is no exception, the Right part runs no problem. However when an exception is thrown, the exception bubbles all the way to the top and Left isn't run. It doesn't seem to mater what kind of exception it is.

Here are the exceptions that is it supposed to catch (though it also won't catch error):

data ParseError                                                                 
    = Unexpected                                                                
    | MalformedRequestLine ByteString                                           
    | MalformedHeader      ByteString                                           
    | MissingHeader        ByteString Headers                                   
    | UnknownSIPVersion    ByteString                                           
      deriving (Typeable, Show, Eq)    

instance Exception ParseError

Here is the type of exceptionHandler:

exceptionHandler :: (ByteString -> IO ())                                         
             -> ParseError                                                    
             -> IO ()

Also this is version 7.4.1 of ghc.

Any ideas why?

Upvotes: 0

Views: 162

Answers (2)

hammar
hammar

Reputation: 139890

I suspect the problem is that you're using a throw which doesn't get evaluated within the scope of the try. In that case, you will get the exception after the try instead, when you try to use the result. If you can, use throwIO instead to ensure that the exception gets thrown at the correct time.

Notice the difference:

> :set -XDeriveDataTypeable
> :m + Control.Exception Data.Typeable
> data Boom = Boom deriving (Show, Typeable)
> instance Exception Boom
> try $ return (throw Boom) :: IO (Either Boom Int)
Right *** Exception: Boom
> try $ throwIO Boom :: IO (Either Boom Int)
Left Boom

Upvotes: 7

Thomas M. DuBuisson
Thomas M. DuBuisson

Reputation: 64740

Your question pains me because if you use the correct try it should work, but you have failed to provide a minimum example. Instead, I will provide a functional example and leave it to you to determine what is different in your code.

{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables #-}

I only needed ScopedTypeVariables because I didn't use an explicitly typed function.

import Control.Exception as X
import Data.ByteString as B
import Data.Typeable
import Data.Data

Notice I am using the Control.Exception module, and the try function from there. I suspect your try comes from elsewhere.

data ParseError
    = Unexpected
    | MalformedRequestLine ByteString
    | MalformedHeader      ByteString
    | MissingHeader        ByteString ()
    | UnknownSIPVersion    ByteString
      deriving (Typeable, Show, Eq)

instance Exception ParseError

parseRequest :: IO Int
parseRequest = throw Unexpected

For testing, my parseResult just throws something.

exceptionHandler :: (ByteString -> IO ())
                 -> ParseError
                 -> IO ()
exceptionHandler f p = print p

main = do
  r <- X.try parseRequest
  case r of
    Right i -> print i
    Left (e :: ParseError) -> print ("Caught",e)

And the main routine is pretty boring - just a summary of the important parts of your routine. It runs fine:

$ ghc so.hs
[1 of 1] Compiling Main             ( so.hs, so.o )
Linking so ...
$ ./so
("Caught",Unexpected)

If you modify the exception to a different type you'll see the exception is not caught:

parseRequest :: IO Int
parseRequest = error "This is a different type, and won't be caught by 'ParseError' handlers."

With a result of:

$ ./so
so: This is a different type, thus not caught by 'ParseError' handlers.

If you wish to catch ALL exceptions then you need a type that suffices for that task.

Upvotes: 1

Related Questions