Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can unsafePerformIO be used to write unsafeCoerce?

It's widely understood that unsafePerformIO is not type safe. This is typically demonstrated by using it to implement unsafeCoerce:

box :: IORef a
box = unsafePerformIO (newIORef undefined)
{-# NOINLINE box #-}

unsafeCoerce :: a -> b
unsafeCoerce a = unsafePerformIO $
  writeIORef box a >> readIORef box

As I showed a few years ago, this implementation is not thread-safe. One thread could write to the box, and then another thread could write to the box again before the first thread can read. Oops! How can this be fixed?

like image 513
dfeuer Avatar asked Jul 09 '21 20:07

dfeuer


Video Answer


1 Answers

As I showed once upon a time, the right way to do this is to use coercion through an IORef to produce the unsafeCoerce function itself, rather than to produce individual results of its application.

box :: IORef x
box = unsafePerformIO (newIORef undefined)
-- This NOINLINE is essential. If this binding is inlined,
-- then unsafeCoerce = undefined.
{-# NOINLINE box #-}

unsafeCoerce :: a -> b
unsafeCoerce = unsafePerformIO $
  writeIORef box id >> readIORef box

-- Inlining this wouldn't break anything,
-- but it'd waste time with unnecessary IORef operations.
{-# NOINLINE unsafeCoerce #-}
like image 99
dfeuer Avatar answered Oct 29 '22 05:10

dfeuer