The second and third implementation of atomicModifyIORef' does not keep the semantics of the first implementation
Summary
- The first implementation of
atomicModifyIORef'
(by Joey Adams #5926 (closed)) installs a new value toIORef
before it is forced. - It seems to me that the second implementation (by parcs #8345 (closed)) installs a new value after it is forced.
- Also, the third implementation (by @treeowl) installs a new value after it is forced.
Cc: @simonmar @simonpj @hvr @carter
Steps to reproduce
Load the following file with GHCi:
{-# LANGUAGE BangPatterns #-}
import GHC.IORef
import Debug.Trace
import Data.IORef
f n = (trace "tupple" ((trace "new" n + 1), (trace "ret" ())))
joey ref f = do
b <- atomicModifyIORef ref
(\x -> let (a, b) = f x
in (a, a `seq` b))
putStrLn "swap"
b `seq` return b
parcs ref f = do
b <- atomicModifyIORef ref $ \a ->
case f a of
v@(a',_) -> a' `seq` v
putStrLn "swap"
b `seq` return b
david ref f = do
(_old, (_new, !res)) <- atomicModifyIORef2 ref $
\old -> case f old of
r@(!_new, _res) -> r
putStrLn "swap"
pure res
And type:
> ref <-newIORef (1::Int)
> joey ref f
swap
tupple
new
ret
> parcs ref f
tupple
new
swap
ret
> david ref f
tupple
new
ret
swap
Expected behavior
If I understand correctly, "new" must appear after "swap".
Environment
- GHC version used: 9.4.4
Note
The following code also keeps the semantics of the first implementation:
kazu ref f = do
b <- atomicModifyIORef ref $ \a ->
case f a of
(a, b) -> (a, a `seq` b)
putStrLn "swap"
b `seq` return b
I think that creating a new tuple cannot be avoided to keep the semantics.