
Hi All, I have the situation where I have something like the following: type Foo = TVar Int data Clasp t = Clasp t makeClasp x f = do let c = Clasp x mkWeakRef c (Just (f x)) return c finis p = do atomically $ do x <- readTVar p writeTVar p (x - 1) .... makeClasp p finis .... The Foo object has a greater lifetime than the Clasp. The bit I want you to focus on is the three lines: let c = Clasp x mkWeakRef c (Just (f x)) return c We can only be sure that (f x) will be called after we let go of the returned value if we can be sure that the language implementation preserves the (explicit) sharing of 'c' between the call to mkWeakRef and return. In particular, if the implementation rewrote the fragment as: mkWeakRef (Clasp x) (Just (f x)) return (Clasp x) then the finalizer might be called sooner than we expect. The problem is, that as I read it, making a distinction between the two fragments would be a violation of referential transparency. So here's the question: is there a way of writing this that is guaranteed to work on all correct implementations of Haskell? cheers, T. ps FWIW, the actual situation is that we have a TVar pointing to a record representing a 'page' of an external data structure. For some operations we need to make sure the the page is in-memory, but when all the operations using a particular page are finished, we'd like to flush it back to disk if it has been modified. Now it'd be really nice to use the garbage collector to tell us when noone is using the in-memory version of the page, so we can write it out. However, if we can't be certain that we've got a genuine hard-reference to the object, then we can't be sure it will not be prematurely flushed. -- Dr Thomas Conway You are beautiful; but learn to work, drtomc@gmail.com for you cannot eat your beauty. -- Congo proverb
participants (1)
-
Thomas Conway