
This proposal is to add two new variations on unsafePerformIO and one new form of unsafeInterleaveIO to the System.IO.Unsafe module in the base library (which already exports unsafePerformIO and unsafeInterleaveIO). The additions are documented and portable to non-ghc. Summary and documentation below, see patch attached to the ticket for code details. http://hackage.haskell.org/trac/ghc/ticket/2095 Suggested timescale: ~2 weeks, ends Friday 29th February Summary * unsafeDupablePerformIO and unsafeDupableInterleaveIO When GHC added SMP support the previous unsafePerform/InterleaveIO got renamed to these two functions and new unsafePerform/InterleaveIO functions were added that provide protection against duplication in a multi-threaded context. This protection comes at some cost so there are cases where it is ok to uses these weaker forms if duplicating the IO action is safe. These are already defined and documented in GHC.IOBase, this patch just exports them. * unsafeInlinePerformIO This is an even less safe form of unsafePerformIO. It is used in the Data.ByteString implementation and is very occasionally needed in other projects. If it is needed it is better that it be supplied in a portable form from a standard module with a sensible name and with full documentation. Haddock Documentation This version of 'unsafePerformIO' is slightly more efficient, because it omits the check that the IO is only being performed by a single thread. Hence, when you write 'unsafeDupablePerformIO', there is a possibility that the IO action may be performed multiple times (on a multiprocessor), and you should therefore ensure that it gives the same results each time. unsafeDupablePerformIO :: IO a -> a TODO: Actually, unsafeDupableInterleaveIO is not yet documented, that will have to be fixed. unsafeDupableInterleaveIO :: IO a -> IO a This variant of 'unsafePerformIO' is quite /mind-bogglingly unsafe/. It unstitches the dependency chain that holds the IO monad together and breaks all your ordinary intuitions about IO, sequencing and side effects. Avoid it unless you really know what you are doing. It is only safe for operations which are genuinely pure (not just externally pure) for example reading from an immutable foreign data structure. In particular, you should do no memory allocation inside an 'unsafeInlinePerformIO' block. This is because an allocation is a constant and is likely to be floated out and shared. More generally, any part of any IO action that does not depend on a function argument is likely to be floated to the top level and have its result shared. It is more efficient because in addition to the checks that 'unsafeDupablePerformIO' omits, we also inline. Additionally we do not pretend that the body is lazy which allows the strictness analyser to see the strictness in the body. In turn this allows some re-ordering of operations and any corresponding side-effects. With GHC it compiles to essentially no code and it exposes the body to further inlining. unsafeInlinePerformIO :: IO a -> a