Discussion: New atomic IORef functions

David Feuer david.feuer at gmail.com
Sat Jul 7 19:09:33 UTC 2018


Whoops! I left out the proposal link:

https://github.com/ghc-proposals/ghc-proposals/pull/149

Also, what I called atomicModifyIORef_ below should really be called
something like atomicModifyIORef'_, since it forces a polymorphic value.

Another thing to note: the underlying atomicModifyMutVar2# primop actually
supports more than just pairs. It can handle triples, solos, and any other
record types whose first components are lifted:

atomicModifyIORefSoloLazy
  :: IORef a -> (a -> Solo a) -> IO (Solo a)

atomicModifyIORefSolo
  :: IORef a -> (a -> Solo a) -> IO a

atomicModifyIORef3, atomicModifyIORef3Lazy
  :: IORef a -> (a -> (a, b, c)) -> IO (a, b, c)

etc.

Should we add any such?

On Sat, Jul 7, 2018, 2:35 PM David Feuer <david.feuer at gmail.com> wrote:

> 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.
>
> The new primops lead naturally to several thin wrappers:
>
> -- Atomically replace the IORef contents
> -- with the first component of the result of
> -- applying the function to the old contents.
> -- Return the old value and the result of
> -- applying the function, without forcing the latter.
> --
> -- atomicModifyIORef ref f = do
> --   (_old, ~(_new, res)) <- atomicModifyIORef2Lazy ref f
> --   return res
> atomicModifyIORef2Lazy
>   :: IORef a -> (a -> (a, b)) -> IO (a, (a, b))
>
> -- Atomically replace the IORef contents
> -- with the result of applying the function
> -- to the old contents. Return the old and
> -- new contents without forcing the latter.
> atomicModifyIORefLazy_
>   :: IORef a -> (a -> a) -> IO (a, a)
>
> -- Atomically replace the IORef contents
> -- with the given value and return the old
> -- contents.
> --
> -- atomicWriteIORef ref x = void (atomicSwapIORef ref x)
> atomicSwapIORef
>   :: IORef a -> a -> IO a
>
> Based on the code I've read that uses atomicModifyIORef, I believe that
> the complete laziness of atomicModifyIORef2Lazy and atomicModifyIORefLazy_ is
> very rarely desirable. I therefore believe we should also (or perhaps
> instead?) offer stricter versions:
>
> atomicModifyIORef2
>   :: IORef a -> (a -> (a, b)) -> IO (a, (a, b))
> atomicModifyIORef2 ref f = do
>   r@(_old, (_new, _res)) <- atomicModifyIORef2Lazy ref f
>   return r
>
> atomicModifyIORef_
>   :: IORef a -> (a -> a) -> IO (a, a)
> atomicModifyIORef_ ref f = do
>   r@(_old, !_new) <- atomicModifyIORefLazy_ ref f
>   return r
>
> The classic atomicModifyIORef also admits a less gratuitously lazy version:
>
> atomicModifyIORefNGL
>   :: IORef a -> (a -> (a,b)) -> IO b
> atomicModifyIORefNGL ref f = do
>   (_old, (_new, res)) <- atomicModifyIORef2 ref f
>   return res
>
> 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.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/libraries/attachments/20180707/94119547/attachment.html>


More information about the Libraries mailing list