Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What advantages do StableNames have over reallyUnsafePtrEquality#, and vice versa?

Tags:

haskell

ghc

data StableName a

Stable names have the following property: If sn1 :: StableName and sn2 :: StableName and sn1 == sn2 then sn1 and sn2 were created by calls to makeStableName on the same object.

The reverse is not necessarily true: if two stable names are not equal, then the objects they name may still be equal.

reallyUnsafePtrEquality# :: a -> a -> Int#

reallyUnsafePtrEquality# returns whether two objects on the GHC heap are the same object. It's really unsafe because the garbage collector moves things around, closures, etc. To the best of my knowledge, it can return false negatives (it says two objects aren't the same, but they are), but not false positives (saying they're the same when they aren't).

Both of them seem to do the same basic thing: they can tell you whether two objects are definitely the same, but not whether they're definitely not.

The advantages I can see for StableNames are:

  • They can be hashed.
  • They are less nonportable.
  • Their behaviour is well-defined and supported.
  • They don't have reallyUnsafe as part of their name.

The advantages I can see for reallyUnsafePtrEquality#:

  • It can be called directly on the objects in question, instead of having to create separate StablesNames.
  • You don't have to go through an IO function to create the StableNames.
  • You don't have to keep StableNames around, so memory usage is lower.
  • The RTS doesn't have to do whatever magic it does to make the StableNames work, so performance is presumably better.
  • It has reallyUnsafe in the name and a # at the end. Hardcore!

My questions are:

  • Did I miss anything?

  • Is there any use case where the fact that StableNames are separate from the objects they name is an advantage?

  • Is either one more accurate (less likely to return false negatives) than the other?

  • If you don't need hashing, don't care about portability, and aren't bothered by using something called reallyUnsafe, is there any reason to prefer StableNames over reallyUnsafePtrEquality#?

like image 212
glaebhoerl Avatar asked Mar 10 '12 19:03

glaebhoerl


1 Answers

Holding the StableName of an object doesn't prevent it from being garbage collected, whereas holding the object itself around (to use with reallyUnsafePtrEquality# later) does. Sure, you can use System.Mem.Weak, but at that point, why not just use a StableName? (In fact, weak pointers were added with StableNames.)

Being able to hash them is the main motivator for StableNames, as the documentation says:

We can't build a hash table using the address of the object as the key, because objects get moved around by the garbage collector, meaning a re-hash would be necessary after every garbage collection.

In general, if StableNames will work for your purposes, I'd use them, even if you need to use unsafePerformIO; if you really need reallyUnsafePtrEquality#, you'll know. The only example I can think of where reallyUnsafePtrEquality# would work and StableNames wouldn't is speeding up an expensive Eq instance:

x == y =
    x `seq` y `seq`
    case reallyUnsafePtrEquality# x y of
        1# -> True
        _  -> slowEq x y

There's probably other examples I just haven't thought of, but they're not common.

like image 52
ehird Avatar answered Sep 21 '22 14:09

ehird