Question

There's code that reads an IORef and based on some conditions and calculations, creates a new value. Now it writes the new value to that IORef. But there is a chance that it didn't get changed at all. The new value may be identical to the old.

What are the considerations regarding whether to check to see if the value is different before writing the IORef, or just write the IORef regardless?

Does writeIORef check to see if the value is changed before setting?

By checking first, could you avoid the write and save a little on performance possibly?

Was it helpful?

Solution

Does writeIORef check to see if the value is changed before setting?

No. writeIORef wraps writeSTRef, which is defined as

-- |Write a new value into an 'STRef'
writeSTRef :: STRef s a -> a -> ST s ()
writeSTRef (STRef var#) val = ST $ \s1# ->
    case writeMutVar# var# val s1#      of { s2# ->
    (# s2#, () #) }

By checking first, could you avoid the write and save a little on performance possibly?

What are the considerations regarding whether to check to see if the value is different before writing the IORef, or just write the IORef regardless?

This is really contingent on the algorithm in question. What are you trying to optimize for? What is the frequency/ratio of reads to writes? what kind of data are you storing? how is it packed? what is the cost of an equality comparison for the data in question?

There exists a whole host of factors to be taken into account when determining whether or not you want to destructively update cells in-place: some algorithm specific, some depending on cache locality, others depending on the structure and form of the code GHC generates. As such, it's exceedingly difficult to answer your question.

A quote from Donald Knuth:

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil

Unless you're at the stage where you're trying to eek out every modicum of performance from some well-understood implementation, you're probably better off picking the path that is

  • simplest to implement
  • easiest to reason about

and getting on with it. If you are at the stage where you'd like to tweak your program, I'd suggest learning to read GHC's human-readable generated output (Core), as you'd then be in the position to make these sorts of decisions (on a very granular level) on a per-program basis.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top