Search code examples
haskellconcurrencyiorefglobal-state

What is the purpose of the extra result parameter of atomicModifyIORef?


The signature of modifyIORef is straightforward enough:

modifyIORef :: IORef a -> (a -> a) -> IO ()

Unfortunately, this is not thread safe. There is an alternative that adresses this issue:

atomicModifyIORef :: IORef a -> (a -> (a,b)) -> IO b

What exactly are the differences between these two functions? How am I supposed to use the b parameter when modifying an IORef that might be read from another thread?


Solution

  • As you stated in a comment, without concurrency you'd be able to just write something like

    modifyAndReturn ref f = do
      old <- readIORef ref
      let !(new, r) = f old
      writeIORef r new
      return r
    

    But in a concurrent context, someone else could change the reference between the read and the write.