Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I make my Haskell modules Safe by default?

Tags:

haskell

ghc

Is there any downside to marking the modules Safe? Should it be the assumed default?

like image 871
Bartek Banachewicz Avatar asked Oct 03 '18 18:10

Bartek Banachewicz


1 Answers

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.

  1. You can only import modules which are also marked Safe (which rules out functions like unsafeCoerce or unsafePerformIO).
  2. You can't use Template Haskell.
  3. You can't use FFI outside of IO.
  4. You can't use GeneralisedNewtypeDeriving.
  5. You can't manually implement the Generic typeclass for the types you define in your module.
  6. etc.

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, the unsafePerformIO :: 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 imports M 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.

like image 103
typetetris Avatar answered Sep 16 '22 19:09

typetetris