Comparisment

   - compare programming languages by example

51

Catching exceptions

The syntax for catching exceptions.

Created by sam

Add a new answer

Either add an answer for a new language or add an alternative solution.
A description is only necessary when the code is not suitably 'obvious' or to justify an alternative approach.

Haskell

import Control.Exception

unsafeDivide :: Int -> Int -> Int
unsafeDivide x 0 = error "Division by zero!"
unsafeDivide x y = x `div` y

tryDivide :: Int -> Int -> IO ()
tryDivide x y =
  let str = catch (show $ unsafeDivide x y)
                  (\err -> show err)
     in putStrLn str

'error' will cause an otherwise pure value to throw an exception when evaluated which can be caught with 'catch' from 'Control.Exception' in 'IO'. Normally, however, it would be better to opt for a more Haskell-y alternative such as using 'Maybe' or 'Either' types to explicitly denote failure that the caller may pattern match upon.

Created by: sam

Edit this answer

Edit the language, code and description simultaneously.

Haskell

divM :: Monad m => m Int
divM x 0 = fail "Division by zero!"
divM x y = return $ x `div` y

-- Failure => Nothing
maybeDivide :: Int -> Int -> Maybe Int
maybeDivide = divM

-- Failure => Left string
eitherDivide :: Int -> Int -> Either String Int
eitherDivide = divM

-- Failure => Throw IO Exception
ioDivide :: Int -> Int -> IO Int
ioDivide = divM

If your function is in any (or a specific) type which is an instance of 'Monad', you may use 'fail' in place of 'error' to delegate the specifics of how failure is handled to the monad instance.

Created by: sam

Edit this answer

Edit the language, code and description simultaneously.

Haskell

safeDivide :: Int -> Int -> Maybe Int
safeDivide x 0 = Nothing
safeDivide x y = Just (x `div` y)

tryDivide :: Int -> Int -> IO ()
tryDivide x y = case safeDivide x y of
  Nothing -> putStrLn "Divide by zero!"
  Just z  -> print z

Instead of throwing an exception, failure is denoted by the 'Nothing' constructor and success by 'Just'. This way, we require that the caller must explicitly handle the failure case.

Created by: sam

Edit this answer

Edit the language, code and description simultaneously.

Haskell

safeDivide :: Int -> Int -> Either String Int
safeDivide x 0 = Left "Division by zero!"
safeDivide x y = Right (x `div` y)

tryDivide :: Int -> Int -> IO ()
tryDivide x y = case safeDivide x y of
  Left err
    -> putStrLn err
  
  Right z
    -> print z

Instead of throwing an exception, failure is denoted by the 'Left' constructor (which takes a failure reason as a string) and success by 'Right'. This way, we require that the caller must explicitly handler the failure case. As opposed to using a 'Maybe' type the caller is also given a reason for failure.

Created by: sam

Edit this answer

Edit the language, code and description simultaneously.

Haskell

data DivError = DivideByZero

safeDivide :: Int -> Int -> Either DivError Int
safeDivide x 0 = Left DivideByZero
safeDivide x y = Right (x `div` y)

tryDivide :: Int -> Int -> IO ()
tryDivide x y = case safeDivide x y of
  Left DivideByZero
    -> putStrLn "Divide by zero!"
  
  Right z
    -> print z

Instead of throwing an exception, failure is denoted by the 'Left' constructor (which takes a failure reason as user defined data type) and success by 'Right'. This way, we require that the caller must explicitly handler the failure case. As opposed to using a 'Maybe' type the caller is also given a reason for failure which is denoted by a custom data type.

Created by: sam

Edit this answer

Edit the language, code and description simultaneously.

Haskell

import Control.Monad.Error

data AdmittanceError
  = TooTall
  | TooShort
  | RefusedForReason String
  | RefusedForNoReason

instance Error AdmittanceError where
  noMsg      = RefusedForNoReason
  strMsg str = RefusedForReason str

rideRollerCoaster :: MonadError AdmittanceError m => Int -> String -> m ()
rideRollerCoaster height name
  | height < 4    = throwError TooShort
  | height > 8    = throwError TooTall
  | name == "Eve" = throwError $ RefusedForReason "You're banned!"
  | otherwise     = return ()

tryRideRollerCoasterIO :: Int -> String -> IO ()
tryRideRollerCoasterIO height name = do
  exclaimation <- catchError (rideRollerCoaster height name >> return "FUN")
                             (\err -> return $ case err of
                               TooTall
                                 -> "I can slouch!?"
                               
                               TooShort
                                 -> "Tiptoes?"

                               _ -> ":("
                             )
  putStrLn exclaimation

Declare custom exception types which can be thrown with 'Control.Monad.Error's 'throwError' and caught with 'catchError'.

Created by: sam

Edit this answer

Edit the language, code and description simultaneously.

Python

def raiseAnException():
  raise Exception("I have an exception!")

def catchYourException():
  try: raiseAnException()
  except Exception as e:
    print("Your exception is handled!")
  finally:
    print("..and we've cleaned up any mess we made to do so!")

Catch a very general exception within a 'try' block. Multiple 'except' clauses can be used to match on the exception type. It isn't possible to catch this exception without having to handle all others and so is not recommended. Instead throw a more specific exception.

Created by: sam

Edit this answer

Edit the language, code and description simultaneously.

Python

def raiseAnException():
  raise ValueError("I have an exception!")

def catchYourException():
  try: raiseAnException()
  except ValueError as v:
    print("Your exception is handled!")
  except Exception as e:
    print("Handling every other exception!")
  finally:
    print("..and we've cleaned up any mess we made to do so!")

Catch a more specific exception from the standard hierarchy within a 'try' block.

Created by: sam

Edit this answer

Edit the language, code and description simultaneously.

Python

class IHaveAnException(Exception):
  pass

def raiseAnException():
  raise IHaveAnException("I have an exception!")

def catchYourException():
  try: raiseAnException()
  except IHaveAnException as v:
    print("Your exception is handled!")
  except Exception as e:
    print("Handling every other exception!")
  finally:
    print("..and we've cleaned up any mess we made to do so!")

Catch a more specific custom exception within a 'try' block.

Created by: sam

Edit this answer

Edit the language, code and description simultaneously.