-
Notifications
You must be signed in to change notification settings - Fork 15
Description
I really like the idea of unsafePartialBecause, but I think it makes an erroneous assumption that the try-catch block it uses will always catch errors arising from incorrect use of whatever thing it is you're passing to it. This is often the case but not always:
module Main where
import Prelude
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (log)
import Control.Monad.Eff.Exception (EXCEPTION, catchException, message)
import Partial.Unsafe (unsafePartialBecause)
import Unsafe.Coerce (unsafeCoerce)
data Foo
= Foo
| Bar
f :: Partial => Foo -> String
f Foo = "Foo"
main = do
log "Trying for the first time:"
catchAndPrint (\_ -> unsafePartialBecause "1" (f Bar))
log "Trying for the second time:"
catchAndPrint (\_ -> (unsafePartialBecause "2" f) Bar)
catchAndPrint act = do
catchException (\err -> log ("Caught: " <> message err)) (evaluate act >>= log)
evaluate :: forall eff a. (Unit -> a) -> Eff (err :: EXCEPTION | eff) a
evaluate = unsafeCoerceIn general it's not safe to assume that the try-catch block will be invoked if the provided function is used incorrectly. Note that the example above is not the only way it can bite you: since functions with a Partial constraint are not required to throw on invalid inputs, these functions will cause unsafePartialBecause to not work as expected either. Take e.g. unsafeIndex from arrays, which returns undefined on an invalid input.
Another issue is that unsafePartialBecause will not interact well with code that uses e.g. catchException.
At the very least we need to update the docs, but I think this behaviour is unintuitive and potentially confusing enough that we should consider removing it altogether.