<html><head></head><body><div class="gmail_quote">On November 21, 2016 12:32:03 AM GMT+11:00, Bertram Felgenhauer via Haskell-Cafe <haskell-cafe@haskell.org> wrote:<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<pre class="k9mail">raichoo via Haskell-Cafe wrote:<br /><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;"> First of all the documentation of `hashStableName` says the following:<br /> <br /> The Int returned is not necessarily unique; several StableNames may map<br /> to the same Int (in practice however, the chances of this are small, so<br /> the result of hashStableName makes a good hash key).<br /></blockquote><br /><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;"> OK, sounds fine, let's put this to the test. So I wrote a little program.<br /> <br />     module Main where<br /> <br />     import Control.Monad<br /> <br />     import System.Mem.StableName<br />     import System.Environment<br /> <br />     main :: IO ()<br />     main = do<br />       args <- getArgs<br />       res <- forM [0..10000] $ \i -> do<br />         x <-
makeStableName i<br />         let h' = hashStableName x<br />         unless (null args) $<br />           print h'<br />         return h'<br /> <br />       putStrLn "---------------------------"<br />       print $ minimum res<br />       print $ maximum res<br /></blockquote><br />There is nothing in this program that keeps the stable names alive.<br />It appears, from your experiments, that once a stable name is garbage<br />collected, its ID, which also serves as its hash value, may be reused<br />for another stable pointer. Consider this variant of your main function:<br /><br />    main = do<br />      res <- forM [0..10000] $ fmap hashStableName . makeStableName<br />      performGC<br />      res <- forM [0..10000] $ fmap hashStableName . makeStableName<br />      performGC<br />      res <- forM [0..10000] $ fmap hashStableName . makeStableName<br />      print (minimum res, maximum res)<br /><br />This produces `(1,10001)` as output in my tests.<br /><br />I'm
not sure how exactly `print` affects garbage collections.<br /><br />Overall, I believe the documentation of `hashStableName` is mostly<br />correct, but it would make sense to stress that the statement is<br />only valid for stable names that are currently alive at a particular<br />point in time, not globally for the whole run of a program.<br /><br />Cheers,<br /><br />Bertram<br /><br /><hr /><br />Haskell-Cafe mailing list<br />To (un)subscribe, modify options or view archives go to:<br /><a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br />Only members subscribed via the mailman list are allowed to post.</pre></blockquote></div><br clear="all">I suspect that when print h' isn't called, then `let h' = hashStableName x` stays as a thunk in the list, until you later compute the minimum and maximum. The thunk refers to the stable name, and keeps it from being GCed. So they *are*
all live at the same time.<br>
<br>
When you print h' in the loop body, that forces the hash calculation and discharges the thunk. So the stable name becomes garbage immediately, and once collected the internal id is available for reuse. Perhaps the 1-260 range observed tells you roughly how many iterations of that loop you can get through in the smallest GC generation, on your system.</body></html>