# How do ephermerons and weak hashes work?

**URL:** <https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036>\
**Category:** Questions & Answers\
**Created:** [May 27, 2022, 4:51pm UTC](https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036 "2022-05-27T16:51:56Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![dstorrs](https://avatars.discourse-cdn.com/v4/letter/d/898d66/32.png) [@dstorrs](https://racket.discourse.group/u/dstorrs)\
**Post date:** [May 27, 2022, 4:51pm UTC](https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036/1 "2022-05-27T16:51:56Z")

</div>

I apparently don't understand the concept of unreachability as it applies to the garbage collector.

```scheme
(define h1 (make-ephemeron-hash))
(define h2 (make-weak-hash))

(struct thing (val) #:transparent)

(let ()
  (hash-set! h1
             (~a "foo" "bar") (thing 1) ; strings created with ~a are not interned                           
             )
  (hash-set! h2
             (~a "bar" "baz") (thing 2))

  ; inside the `let`, each hash should contain one k/v pair                                                   
  (pretty-print h1)
  (pretty-print h2))

(sleep 2) ; give it time for unreachability to be noticed                                                     
(collect-garbage) ; force a GC pass, just to be sure                                                          

; both hashes should be empty                                                                                 
(pretty-print h1)
(pretty-print h2)

; Output: 
; (hash "foobar" (thing 1))
; (hash "barbaz" (thing 2))

```

I guess the values are being retained because they are accessible through h1 and h2? That surprises me, since I thought the entire point of these things was to ensure that those hashes _didn't_ count.

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [May 27, 2022, 4:59pm UTC](https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036/2 "2022-05-27T16:59:18Z")

</div>

I get empty hashes for the second printout when I try your program.

Note that the sleep is not needed; nothing concurrent with your program is happening. However, additional garbage collections can cause more things to be unreachable via ephemerons, if the unreachable key was noticed to be unreachable _after_ the ephemeron was visited earlier by the GC.

---

<div class="post-metadata">

**Author:** ![dstorrs](https://avatars.discourse-cdn.com/v4/letter/d/898d66/32.png) [@dstorrs](https://racket.discourse.group/u/dstorrs)\
**Post date:** [May 27, 2022, 5:03pm UTC](https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036/3 "2022-05-27T17:03:03Z")

</div>

> [@samth](#):
>
> I get empty hashes for the second printout when I try your program.

Ohhhkay... I reliably get NON-empty hashes. I'm on Racket 8.4 on macOS 10.15.5, would that matter? If not, where should I be looking?

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [May 27, 2022, 6:02pm UTC](https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036/4 "2022-05-27T18:02:20Z")

</div>

You should try adding a second (or third) call to `collect-garbage` and see if that changes the result.

---

<div class="post-metadata">

**Author:** ![dstorrs](https://avatars.discourse-cdn.com/v4/letter/d/898d66/32.png) [@dstorrs](https://racket.discourse.group/u/dstorrs)\
**Post date:** [May 27, 2022, 6:07pm UTC](https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036/5 "2022-05-27T18:07:48Z")

</div>

Tried it, no change.

---

<div class="post-metadata">

**Author:** ![LiberalArtist](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/liberalartist/32/151_2.png) [@LiberalArtist](https://racket.discourse.group/u/LiberalArtist)\
**Post date:** [May 29, 2022, 4:37am UTC](https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036/6 "2022-05-29T04:37:49Z")

</div>

With Racket 8.5 CS on x86\_64-linux, I also get consistently empty hashes.

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [May 30, 2022, 12:53pm UTC](https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036/7 "2022-05-30T12:53:50Z")

</div>

@dstorrs How are you running the program?

Why I ask:

I get the same result as everyone except you -- empty hash-tables -- when running using command-line Racket, DrRacket, and Racket Mode with `racket-pretty-print` set to `nil`.

But running using Racket Mode with `racket-pretty-print` set to `t`, I see the non-empty hash-tables. What is retaining a reference to the keys? I suspect [this](https://github.com/greghendershott/racket-mode/blob/master/racket/print.rkt#L25-L37). I'll open an issue.

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [May 30, 2022, 1:53pm UTC](https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036/8 "2022-05-30T13:53:43Z")

</div>

> <https://github.com/greghendershott/racket-mode/issues/624>
>
> Arising from https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes…-work/1036/5.
> 
> Given this program:
> 
> 
> \`\`\`racket
> \#lang racket/base
> 
> (require racket/format
> racket/pretty)
> 
> (define h1 (make-ephemeron-hash))
> (define h2 (make-weak-hash))
> 
> (struct thing (val) #:transparent)
> 
> (let ()
> ;; strings created with ~a are not interned
> (hash-set! h1 (~a "foo" "bar") (thing 1)) (hash-set! h2 (~a "bar" "baz") (thing 2))
> 
> ;; inside the \`let\`, each hash should contain one k/v pair
> (pretty-print h1)
> (pretty-print h2))
> 
> (collect-garbage 'major)
> 
> ;; Both hashes should be empty
> (pretty-print h1)
> (pretty-print h2)
> \`\`\`
> 
> When run using command-line Racket, DrRacket, or Racket Mode with \`racket-pretty-print\` set to \`nil\`, it correctly prints:
> 
> \`\`\`
> (hash "foobar" (thing 1))
> (hash "barbaz" (thing 2))
> '#hash()
> '#hash()
> \`\`\`
> 
> When run using Racket Mode with \`racket-pretty-print\` set to \`t\`, it incorrectly prints:
> 
> \`\`\`
> (hash "foobar" (thing 1))
> (hash "barbaz" (thing 2))
> (hash "foobar" (thing 1))
> (hash "barbaz" (thing 2))
> \`\`\`
> 
> \---
> 
> The fix might be as simple as using a weak hash-table ourselves:
> 
> \`\`\`diff
> modified racket/print.rkt
> @@ -34,7 +34,7 @@
> ;; (Note: Although I had tried using the pre-print and post-print
> ;; hooks, they seemed to be called inconsistently.)
>  
> \-(define ht (make-hasheq))
> +(define ht (make-weak-hasheq))
>  
> (define (make-pretty-print-size-hook pixels/char)
> (define (racket-mode-size-hook value \_display? \_port)
> \`\`\`

The fix _might_ be as simple as using a weak hash-table there. But I'll give it a think.

---

<div class="post-metadata">

**Author:** ![dstorrs](https://avatars.discourse-cdn.com/v4/letter/d/898d66/32.png) [@dstorrs](https://racket.discourse.group/u/dstorrs)\
**Post date:** [May 31, 2022, 1:28pm UTC](https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036/9 "2022-05-31T13:28:06Z")

</div>

Aha. Yes, that was the issue. When I run it from the command line it works as expected and as soon as I set `racket-pretty-print` to `nil` it also worked.

Thanks, Greg.

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [May 31, 2022, 6:21pm UTC](https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036/10 "2022-05-31T18:21:33Z")

</div>

I merged a fix yesterday, so that `racket-pretty-print` enabled works, too.

It should already be available on MELPA, whenever you might want to [update Racket Mode](https://www.racket-mode.com/#Update).

---

<div class="post-metadata">

**Author:** ![dstorrs](https://avatars.discourse-cdn.com/v4/letter/d/898d66/32.png) [@dstorrs](https://racket.discourse.group/u/dstorrs)\
**Post date:** [May 31, 2022, 9:57pm UTC](https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036/11 "2022-05-31T21:57:17Z")

</div>

I uninstalled racket-mode as per the directions, then went to reinstall it, and emacs told me "Hey, I can't connect to elpa! Stinks to be you!" This sent me down a rabbit hole of googling to figure out why emacs wasn't able to connect when Firefox could. One solution said that it's an issue with the user-agent string. Another said that I needed to downgrade (!) my OpenSSL library, which is a thing that macOS makes extremely difficult, which is sad since the one that comes on macOS 10.15 is `OpenSSL 1.1.0-pre5-dev xx XXX xxxx` which holy heckfire, the current version is 3.0!!

In the end I simply copied the racket-mode-20211130.1748 directory back into .emacs.d/elpa and called it a day. 😕 It seems to be working, which is bizarre since I reverted the `racket-pretty-print` to be non-nil. I'm going to chalk this one up to "computers are weird, networks are awful, GNU software is user-hostile, and ain't nobody got time for this."

Thanks for pointing me to the fix. If I wanted to git clone the latest racket-mode, what would the appropriate version string be so that I could drop it into .../elpa ?

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [May 31, 2022, 10:26pm UTC](https://racket.discourse.group/t/how-do-ephermerons-and-weak-hashes-work/1036/12 "2022-05-31T22:26:37Z")

</div>

That sounds frustrating. Emacs and TLS isn't my wheelhouse, so my advice for a problem connecting with MELPA would be [their guide](https://melpa.org/#/getting-started), and if still no joy, open an issue [there](https://github.com/melpa/melpa/issues)?
