Skip to content

Fix incorrect usage of catch in pure code #4802

Closed
@lehins

Description

Original comment: #4740 (comment)

This is a horrible piece of code that is totally incorrect:

unsafePerformIO $
r `seq`
pure (pure r) `catch` \(e :: SomeException) -> pure (fatalError (pure $ show e))

  1. It will catch all exceptions, including async exceptions. It should have been catching the ErrorCall exception instead of SomeException, if it needs to catch error calls.

  2. Moreover this code will not even catch error calls because seq happens outside of catch:

ghci> let x = undefined in x `seq` pure x `catch` \e -> putStrLn ("WTH " <> show (e :: SomeException))
*** Exception: Prelude.undefined
CallStack (from HasCallStack):
  undefined, called at <interactive>:8:9 in interactive:Ghci2
ghci> let x = undefined in (x `seq` pure x) `catch` \e -> putStrLn ("WTH ==============\n" <> show (e :: SomeException))
WTH ==============
Prelude.undefined
CallStack (from HasCallStack):
  undefined, called at <interactive>:10:9 in interactive:Ghci3
  1. Moreover, using unsafePerformIO to catch an exception will lead to non-deterministic execution, which can break referential transparency. In other words it is never safe to catch exceptions in pure code with unsafePerformIO

Originally posted by @lehins in #4740 (comment)

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions