<div dir="auto">I'm trying, and failing, to understand why ForeignPtr is defined the way it is. It all seems rather complicated and redundant. I was thinking we might want to switch to something simpler and more explicit, like this:<div dir="auto"><br></div><div dir="auto">data ForeignPtr a = ForeignPtr {</div><div dir="auto">  fptr :: !(Ptr a) -- What we point to</div><div dir="auto">  froot :: MutableByteArray# RealWorld</div><div dir="auto">  fwk :: MutVar# RealWorld Any -- The finalizers</div><div dir="auto">  }</div><div dir="auto"><br></div><div dir="auto">froot represents the object the ForeignPtr points into. When created by one of the malloc variants, this will actually be the allocated byte array. Otherwise, it will be a 0-length array.</div><div dir="auto"><br></div><div dir="auto">fwk should be seen as having type</div><div dir="auto"><br></div><div dir="auto">  fwk :: MutVar# RealWorld (Weak# (MutableByteArray# RealWorld))</div><div dir="auto"><br></div><div dir="auto">but we can't express that directly right now. fwk is keyed on froot, and in the malloc case also points to it, to prevent it from being freed prematurely.</div><div dir="auto"><br></div><div dir="auto">It seems that this representation requires a couple extra primitive features from Weak#. I think that's okay: Weak# already has some primitive features designed to support ForeignPtr.</div><div dir="auto"><br></div><div dir="auto">1. An operation to add a Haskell finalizer to a Weak#, similar to the one that adds a C finalizer.</div><div dir="auto"><br></div><div dir="auto">2. A way to deal with mixed finalizers: either make the finalizer-adding primops report distinguishable failure on mixing or arrange to run the C finalizers after any Haskell finalizers (since C finalizers are much more likely to actually invalidate the pointer).</div><div dir="auto"><br></div><div dir="auto">3. A documented guarantee about the order in which the finalizers attached to a particular Weak# run, compatible with the ForeignPtr documentation.</div></div>