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 = unsafeCoerce
In 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.