Clarifying when exactly ephemerons get 'emptied'

Hello! Ephemerons are not behaving exactly like I am expecting. Based on https://caml.inria.fr/pub/docs/manual-ocaml/libref/Ephemeron.html

The data is considered by the garbage collector alive if all the full keys are alive and if the ephemeron is alive. When one of the keys is not considered alive anymore by the GC, the data is emptied from the ephemeron. The data could be alive for another reason and in that case the GC will not free it, but the ephemeron will not hold the data anymore.

So if I understand that correctly then, if I create an ephemeron with a single key and a single value, then unset the key, the value should be considered to be ‘empty’. However this is not what I am observing, e.g.:

module E = Ephemeron.K1;;

let e = E.create ();;
let test () =
  let k = "a" in
  let d = 1 in
  E.set_key e k;
  E.set_data e d;
  print_endline (string_of_bool (E.check_key e && E.check_data e)); (* true, OK *)
  E.unset_key e;;
test ();;
E.check_key e;; (* false, OK *)
E.check_data e;; (* true, what?! *)

What I am trying to understand is how can the ephemeron’s data be considered ‘full’ or ‘alive’ if its key is empty?

In an ephemeron, the keys are all weak references and the data is a reference that is strong when all the keys are still alive, and weak when one or more of the keys have been collected. In your code sample above, what’s happening is check_key returns false because the key is unset, and check_data is true because it resolves to a value of type int which will never be collected.

Thanks! But, when I make the data a ‘boxed’ value e.g. let d = Some 1 or let d = "data", E.check_data e is still true. So I’m still scratching my head here :slight_smile:

I need to update you again on this–you were right actually! Using a boxed key was indeed partly the answer. My other clue was from here, to do a full GC collection. With these two things, I was able to show in a unit test that the behaviour I described in Use Case for Ephemerons? is actually happening. Diff in case of interest: https://github.com/yawaramin/re-web/commit/e51fc836e9c4f59a96f599252cac21c399b45e55#diff-3fd5d52226a6bee323695d95b97dce6c

1 Like