Discussion: New atomic IORef functions

Dr.Koster drkoster at qq.com
Wed Jul 11 18:22:05 UTC 2018


But if you force the pair result, you have to evaluate modifying function isn't it? That's sometime unwanted when you have an very expensive f here, let's say a deep binary search which might not depend previous result.


I think that is also why current atomicModifyIORef is designed this way, so I'd rather keep it the old way.


发自我的iPhone

------------------ Original ------------------
From: David Feuer <david.feuer at gmail.com>
Date: Thu,Jul 12,2018 0:51 AM
To: winter <drkoster at qq.com>
Cc: Haskell Libraries <libraries at haskell.org>
Subject: Re: Discussion: New atomic IORef functions



All the fundamental functions I've defined can be usefully used in the base library. I think that's one good reason to put them there. Another is that while the basic array operations have traditionally been exposed through array, vector, and primitive, and the basic TVar operations have been exposed through stm, the basic IORef and MVar operations have been exposed through base (except, for some reason, casMutVar#). I see no reason to change that.


I never proposed a function that forces the previous value unnecessarily, so I don't know why you're complaining about that. The extra laziness I don't like is in the pair result; none of the uses I've seen thus can far make intentional use of that. That's why I tend to think atomicModifyIORef (as it exists today) is almost never what people actually want.


Squeezing into a second component leads to extra allocation in what may be a performance-critical function; that said, I'm willing to hold off on higher tuples for now.

On Sun, Jul 8, 2018, 3:36 AM winter <drkoster at qq.com> wrote:

                   
I believe new variations should always be motivated by use-case       if there're too many choices, the lazy behavior of old       `atomicModifyIORef` is justified by some cases the modifying       functions are lazy in its argument, thus a lazy version could win       by not forcing previous thunks, we'd want to keep its behavior as       how it's documented.
     
     
As for tuples more than pairs, they're not really needed, user       can always squeeze their product into `b` component. 
     
     
IMHO only the addition of `atomicModifyIORef_` is sensible in the       context of base, other APIs may go to package like primitives. But       if you have a motivated use case with `atomicModifyIORef2`, etc.       Please tell me.
     
     On 2018年07月08日 03:09, David Feuer       wrote:
     
            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.
               
             
           
                
       
              
       _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries           
   
 _______________________________________________
 Libraries mailing list
 Libraries at haskell.org
 http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/libraries/attachments/20180712/7e129bf4/attachment.html>


More information about the Libraries mailing list