How does readIORef work: creates copy or it does not?

502 views Asked by At

What exactly does this code do? Is someMap a copy of the object (of ::Data.Map.Strict.Map) referred to by myMap or it's a reference only? I mean can someMap change (by another thread) after I read it with readIORef? Something like C's volatile... Is it possible? I expect that it's copy/snapshot, so any changes will not affect my someMap, or ...?

     do
        ....
        someMap <- readIORef myMap
        ....
2

There are 2 answers

0
Will Ness On BEST ANSWER

readIORef :: IORef a -> IO a, so myMap must be IORef a and readIORef myMap :: IO a.

And so someMap :: a, because it's to the left of <- in the do code line of the type IO a (it's a <- M a, always, in do notation).

In your case, that a ~ Data.Map.Strict.Map k v, i.e. a pure immutable value.

If another thread writes some new value into that myMap :: IORef (Data.Map.Strict.Map k v), then, it does. But it won't change the pure value that was already drawn from it before the switch-up.

Effectful code has time. Pure referentially transparent code with immutable data is timeless.

(What is true, is true, regardless of how long it takes to prove it.)

4
Paul Johnson On

No it is not a copy. In Haskell there is no such thing as a "copy", there are only values and all values are immutable.

An IORef contains a value. The IORef itself is mutable: you can change the value that it contains. The value itself is not mutable. To understand this, think of an IORef Int which currently contains 5. If you get that value out and add one to it to get 6 you have created a new value, but you have not changed the 5 value to have suddenly become 6, because the value of 5 is immutable.

Likewise if I create a Map with the value fromList [("foo", 5), ("bar, 6")] and put it in an IORef, the IORef now contains that value, but the value itself is immutable. If I get the value out and add a new entry using Map.insert I have created a new value, not modified the original value, exactly the same way as with the 5 and 6 above.

Hopefully that answers your question. However you may now have another one. If all values are immutable, how can IORefs change?

The answer is that the IORef itself does not change. However IORefs exist as a kind of portal to the mutable ever-changing chaos that we call "The Real World". In The Real World you can do the same thing twice and get different results. That includes readLine and readIORef. The IO monad exists to quarantine this chaos while still allowing the program to interact with it. Hence every function that works with IORefs is in the IO monad.