Is there any downside to marking the modules Safe
? Should it be the assumed default?
As you can read in the GHC user manual, if you mark your modules Safe
, you are restricted to a certain "safe" subset of the Haskell language.
Safe
(which rules out functions like unsafeCoerce
or unsafePerformIO
).IO
.GeneralisedNewtypeDeriving
.Generic
typeclass for the types you define in your module.In exchange, the users of the module gain a bunch of guarantees (quoting from the manual):
- Referential transparency — The types can be trusted. Any pure function, is guaranteed to be pure. Evaluating them is deterministic and won’t cause any side effects. Functions in the
IO
monad are still allowed and behave as usual. So, for example, theunsafePerformIO :: IO a -> a
function is disallowed in the safe language to enforce this property.- Module boundary control — Only symbols that are publicly available through other module export lists can be accessed in the safe language. Values using data constructors not exported by the defining module, cannot be examined or created. As such, if a module
M
establishes some invariants through careful use of its export list, then code written in the safe language that importsM
is guaranteed to respect those invariants.- Semantic consistency — For any module that imports a module written in the safe language, expressions that compile both with and without the safe import have the same meaning in both cases. That is, importing a module written in the safe language cannot change the meaning of existing code that isn’t dependent on that module. So, for example, there are some restrictions placed on the use of
OverlappingInstances
, as these can violate this property.- Strict subset — The safe language is strictly a subset of Haskell as implemented by GHC. Any expression that compiles in the safe language has the same meaning as it does when compiled in normal Haskell.
Note that safety is inferred. If your module is not marked with any of Safe
, Trustworthy
, or Unsafe
, GHC will infer the safety of the module to Safe
or Unsafe
. When you set the Safe
flag, then GHC will issue an error if it decides the module is not actually safe. You can also set -Wunsafe
, which emits a warning if a module is inferred to be unsafe. If you let it be inferred, your module will continue to compile even if your dependencies' safety statuses change. If you write it out, you promise to your users that the safety status is stable and dependable.
One use case described in the manual refers to running "untrusted" code. If you provide extension points of any kind in your product and you want to make sure that those capabilities aren't used to attack your product, you can require the code for the extension points to be marked Safe
.
You can mark your module Trustworthy
and this doesn't restrict you in any way while implementing your module. Your module might be used from Safe
code then and it is your responsibility to not violate the guaranties, that should be given by Safe
code. So this is a promise, you the author of said module, give. You can use the flag -fpackage-trust
to enable extra checks while compiling modules marked as Trustworthy
described here.
So, if you write normal libraries and don't have a good reason to care about Safe Haskell, then you probably shouldn't care. If your modules are safe, thats fine and can be inferred. If not, then this is probably for a reason, like because you used unsafePerformIO
, which is also fine. If you know your module will be used in a way that requires it to compile under -XSafe
(e.g. plugins, as above), you should do it. In all other cases, don't bother.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With