Search code examples
elixirgen-server

Why it would be better keeping track of #Reference than #PID when implementing a GenServer?


Elixir's Mix and OTP Guide Chapter GenServer explains how to implement a registry server holding agents, using GenServer.

Each agent's PID is kept in a map, where the keys are the agent's names given by the clients and the values are the agent's PIDs.

In order to avoid keeping references to dead agents, the guide proposes monitoring newly created agents using Process.monitor/1 and slightly modifying the state by adding a new map, called refs, containing References (values returned by Process.monitor/1) as keys and agents' names as values. It also shows how to handle monitoring messages using handle_info/2 to update refs.

Process.monitor/1 receives a PID (e.g. #PID<0.66.0>) as a parameter and returns a Reference (e.g. #Reference<0.0.0.551>). The :DOWN message caught by handle_info/2 provides both the PID and the Reference.

Since we know all the time both values: What are the benefits of using References as keys over using PIDs in refs, if any?


Solution

  • This is a matter of consistency. While you have only processes monitored, there is no difference. But underlying :erlang.monitor/2 can monitor not only processes: there are ports etc, that basically have no PID.

    From the doc:

    Object

    The monitored entity, which triggered the event. When monitoring a local process or port, Object will be equal to the pid() or port() that was being monitored. When monitoring process or port by name, Object will have format {RegisteredName, Node} where RegisteredName is the name which has been used with monitor/2 call and Node is local or remote node name (for ports monitored by name, Node is always local node name).

    The summing up: Reference is an entity, being monitored. It might be a process, a port, whatever. While you do not want to demonitor/1 the whole process that closed the port monitored, you should use references.