<div dir="auto">I have proposed[1] the replacement of the atomicModifyMutVar# primop, and the addition of two cheaper but less capable ones. It seems likely that the proposal will succeed, but that the GHC steering committee will leave the question of user interface changes to the libraries list. I would like to open the discussion here.<div dir="auto"><br></div><div dir="auto">The new primops lead naturally to several thin wrappers:</div><div dir="auto"><br></div><div dir="auto">-- Atomically replace the IORef contents</div><div dir="auto">-- with the first component of the result of</div><div dir="auto">-- applying the function to the old contents.</div><div dir="auto">-- Return the old value and the result of</div><div dir="auto">-- applying the function, without forcing the latter.</div><div dir="auto">--</div><div dir="auto">-- atomicModifyIORef ref f = do</div><div dir="auto">--   (_old, ~(_new, res)) <- atomicModifyIORef2Lazy ref f</div><div dir="auto">--   return res</div><div dir="auto">atomicModifyIORef2Lazy</div><div dir="auto">  :: IORef a -> (a -> (a, b)) -> IO (a, (a, b))</div><div dir="auto"><br></div><div dir="auto">-- Atomically replace the IORef contents</div><div dir="auto">-- with the result of applying the function</div><div dir="auto">-- to the old contents. Return the old and</div><div dir="auto">-- new contents without forcing the latter.</div><div dir="auto">atomicModifyIORefLazy_</div><div dir="auto">  :: IORef a -> (a -> a) -> IO (a, a)</div><div dir="auto"><br></div><div dir="auto">-- Atomically replace the IORef contents</div><div dir="auto">-- with the given value and return the old</div><div dir="auto">-- contents.</div><div dir="auto">--</div><div dir="auto">-- atomicWriteIORef ref x = void (atomicSwapIORef ref x)</div><div dir="auto">atomicSwapIORef</div><div dir="auto">  :: IORef a -> a -> IO a</div><div dir="auto"><br></div><div dir="auto">Based on the code I've read that uses atomicModifyIORef, I believe that the complete laziness of <span style="font-family:sans-serif">atomicModifyIORef2Lazy</span> and <span style="font-family:sans-serif">atomicModifyIORefLazy_</span> is very rarely desirable. I therefore believe we should also (or perhaps instead?) offer stricter versions:</div><div dir="auto"><br></div><div dir="auto"><div dir="auto" style="font-family:sans-serif">atomicModifyIORef2</div><div dir="auto" style="font-family:sans-serif">  :: IORef a -> (a -> (a, b)) -> IO (a, (a, b))</div><div dir="auto" style="font-family:sans-serif">atomicModifyIORef2 ref f = do</div><div dir="auto" style="font-family:sans-serif">  r@(_old, (_new, _res)) <- atomicModifyIORef2Lazy ref f</div><div dir="auto" style="font-family:sans-serif">  return r</div><div dir="auto" style="font-family:sans-serif"><br></div><div dir="auto" style="font-family:sans-serif"><div dir="auto">atomicModifyIORef_</div><div dir="auto">  :: IORef a -> (a -> a) -> IO (a, a)</div><div dir="auto">atomicModifyIORef_ ref f = do</div><div dir="auto">  r@(_old, !_new) <- atomicModifyIORefLazy_ ref f</div><div dir="auto">  return r</div><div dir="auto"><br></div><div dir="auto">The classic atomicModifyIORef also admits a less gratuitously lazy version:</div><div dir="auto"><br></div><div dir="auto">atomicModifyIORefNGL</div><div dir="auto">  :: IORef a -> (a -> (a,b)) -> IO b</div><div dir="auto">atomicModifyIORefNGL ref f = do</div><div dir="auto">  (_old, (_new, res)) <- atomicModifyIORef2 ref f</div><div dir="auto">  return res</div><div dir="auto"><br></div><div dir="auto">Should we add that as well (with a better name)? Should we even consider *replacing* the current atomicModifyIORef with that version? That could theoretically break existing code, but I suspect it would do so very rarely. If we don't change the existing atomicModifyIORef now, I think we should consider deprecating it: it's very easy to accidentally use it too lazily.</div></div></div></div>