Skip to content

Reconsider unsafePartialBecause #7

Closed
@hdgarrood

Description

@hdgarrood

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.

Thoughts? /cc @chexxor @sharkdp

Metadata

Metadata

Assignees

No one assigned

    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