Hi Facundo,
> I propose dropping unsafe uses of Dynamic, because I don't think it
> achieves any compatibility in the face of future changes. IIUC every
> user of Dynamic or DynStaticPtr would be forced to use unsafeCoerce at
> some point and this in turn would materialize code that needs to be
> changed when the interface is made truly safe.
> Code like: unsafeCoerce $ (fromJust $ fromDyn d :: ()) :: StaticPtr
YourType
I am not fussed either way, as long as unsafeCoerce or
unsafeLookupStaticPtr are hidden in the Closure library.
Related to this: In a recent email exchange about your commit Simon
wrote
> So the big question is: what if there is a (static e) in a splice?
> Thus $(f (static x))? For now I suggest you simply make this illegal.
> Because you have to run that splice, so you don’t want to generate C
> constructor functions, stub files etc. Indeed initDsTc should really
> check that it doesn't need any of these fancy things.
I find this is somewhat alarming, for the following reason:
Suppose I want `static e :: StaticPtr t` where `t` is polymorphic (and
hence not Typeable). Because the type checker adds a `Typeable t`
constraint, I have to actually write
unsafeCoerce (static (unsafeCoerce e :: ())) :: StaticPtr t
I can't have users write unsafeCoerce, let alone double unsafeCoerce.
Fortunately, this code can be hidden in the HdpH mkClosure macro,
but only if I can use static inside TH splices.
> I think that Patrick contributions deserve attention. Is there a need
> to add them in the interim version? The FFI could be used to access
> the SPT in the RTS to experiment with variants of the API.
HdpH would like to serialise StaticPtrs as indices into the SPT rather
than as Fingerprints. I don't know whether the API of the RTS hash table
that you are using admits these accesses. But in the interim there is
another solution: add an array with all the StaticKeys, and expose
indexToStaticKey :: Int -> StaticKey
sptKeysToAscList :: [(Int, StaticKey)]
`sptKeysToAscList` is exactly what one needs for fingerprinting the SPT.
Plus, it is needed to implement `staticKeyToIndex :: StaticKey -> Int`,
which is the inverse of `indexToStaticKey`, by search through the list.
The search looks inefficient but it'll happen only once per StaticPtr
if you store `staticKeyToIndex fp` in an extra field of the `StaticPtr`
constructor. So I suggest to define `StaticPtr` as
data StaticPtr a = StaticPtr
{ staticPtrKey :: !StaticKey
, staticPtrIndex :: Int -- deliberately non-strict
, staticPtrInfo :: StaticPtrInfo
, deRefStaticPtr :: a }
mkStaticPtr :: StaticKey -> StaticPtrInfo -> a -> StaticPtr a
mkStaticPtr fp nfo e = StaticPtr fp (staticKeyToIndex fp) nfo e
-- Does `mkStaticPtr` need to execute before `sptKeysToAscList`
-- is accessible, eg. in TH splices? That should be fine, thanks to
-- `staticPtrIndex` being non-strict.
> We certainly could consider augmenting the StaticPtrInfo datatype with
> more information deemed essential.
For usability, the source location of the static expression would be
helpful.
How do you compute the StaticKey? I propose to compute the key from
a unique module identifier (pkgName-pkgVersion-fully.qualified.moduleName)
and a hash of the (canonicalised) source code of the static expression.
Using a fresh name instead of the source hash is ok in the interim,
but using a unique module identifier is crucial. Otherwise you might
get into trouble if an application depends on multiple versions of the
same package.
Great work, by the way.
Cheers,
Patrick