In-place update in IO

Is there a (low-level) GHC feature which will allow an in-place update of a particular constructor/record field in an IORef, for efficiency?

Given the following code:

data Object = Object {
    field1 :: Int
    field2 :: VeryLargeDataType
    }

main :: IO ()
main = do
    var <- newIORef
    writeIORef var $ Object {
             field1 = 42,
             field2 = lotsOfData
        }
    modifyIORef var (\a -> a { field1 = (field1 a + 1) } )
    ...

GHC will read out the very large object, perform the trivial modification, and write it back.

In theory, an in-place update of just the field would be sufficient, and far more efficient.

Is there any GHC feature, e.g. a low-level primitive, that would allow me to do this for any ADT?

I know the special-case solution is to make ther fields IORefs rather than the structure, but I’m looking for a way to do this with any structure, including from a library.

1 Like

It sounds like you want the mutable constructor fields proposal. This would introduce precisely what you want. At this point it is merely looking for an implementor (although I believe Iavor Diatchki and Ryan Yates both have (stalled?) work-in-progress implementations).

2 Likes

I was surprised to find that the mutable constructor fields proposal didn’t have an implementation tracking ticket. I have opened GHC #19387 to fill this role and pinged both Iavor and Ryan. Hopefully they will pop up soon.

1 Like

Mutable fields are very cool!

But in this case is there anything to worry about? field2 will be a pointer to the very large thing so updating the other field will still be cheap.

True. I simplified slightly. It matters more when Object has a large number of fields (broad, rather than deep.)

1 Like

I’m understanding MutableFields still requires fields to be declared mutable but not a way of ‘lifting’ a pure type into mutable. (Although you could probablyy enable it with some generic code).

Is there a conceptual problem with this idea?

Mutating an otherwise immutable datatype would be bad unless you have some kind of single-use guarantees (linearity).

Which would let the compiler ‘know’ its inside an IORef.

So we need to wait for a union of MutableFields and broader adoption of LinearTypes.