Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,24 @@

### Types

data Exception :: * -> !
data Error :: *

data Exception :: !


### Type Class Instances

instance showError :: Show Error


### Values

catchException :: forall e r a. (e -> Eff r a) -> Eff (err :: Exception e | r) a -> Eff r a
catchException :: forall a eff. (Error -> Eff eff a) -> Eff (err :: Exception | eff) a -> Eff eff a

error :: String -> Error

message :: Error -> String

showErrorImpl :: Error -> String

throwException :: forall a e r. e -> Eff (err :: Exception e | r) a
throwException :: forall a eff. Error -> Eff (err :: Exception | eff) a
32 changes: 28 additions & 4 deletions src/Control/Monad/Eff/Exception.purs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,34 @@ module Control.Monad.Eff.Exception where

import Control.Monad.Eff

foreign import data Exception :: * -> !
foreign import data Exception :: !

foreign import data Error :: *

instance showError :: Show Error where
show = showErrorImpl

foreign import showErrorImpl
"function showErrorImpl(err) {\
\ return err.stack ? err.stack : err.toString();\
\}" :: Error -> String

foreign import error
"function error(msg) {\
\ return new Error(msg);\
\};" :: String -> Error

foreign import message
"function message(e) {\
\ return e.message;\
\}" :: Error -> String

foreign import throwException
"function throwException(e) {\
\ return function() {\
\ throw e;\
\ };\
\}" :: forall a e r. e -> Eff (err :: Exception e | r) a
\}" :: forall a eff. Error -> Eff (err :: Exception | eff) a

foreign import catchException
"function catchException(c) {\
Expand All @@ -18,8 +38,12 @@ foreign import catchException
\ try {\
\ return t();\
\ } catch(e) {\
\ return c(e)();\
\ if (e instanceof Error) {\

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the expected semantics here?

When would e not be an Error? If someone throws something that isn't in the Error hierarchy? Could we wrap that thing in an Error and handle it immediately, rather than throwing something we can't actually catch?

if (e instanceof Error) {
  return c(e)();
} else {
  return c(new Error(e))();
}

As it is now. This is a runtime exception we can't actually handle.

Unfortunately, it's also not a matter of wrapping the library throwing the non-error and calling it a day. This check will fail in NodeWebKit, since it uses two different contexts with different prototypes. So, what is thrown as an Error on the node side, will not be an instance of the window's Error because the prototypes are different. There's no way around this prototypal difference

I understand you shouldn't be concerned with what some random library does, but I think this happens for anything with a different context, like iframes, so, this might be more painful than first thought.

\ return c(e)();\
\ } else {\
\ throw e;\
\ }\
\ }\
\ };\
\ };\
\}" :: forall e r a. (e -> Eff r a) -> Eff (err :: Exception e | r) a -> Eff r a
\}" :: forall a eff. (Error -> Eff eff a) -> Eff (err :: Exception | eff) a -> Eff eff a