Using atoms as pids in Elixir

When starting a GenServer process via its start_link/3 API, we're given a pid when the call succeeds:

{:ok, pid} = GenServer.start_link(MyModule, %{})
# {:ok, #PID<0.980.0>}

A call to start_link/3 is often abstracted into the GenServer module that is being created.

If we want to only start a single process for our module in our application, we can utilize the name option:

defmodule MyModule do
  use GenServer

  @impl true
  def init(state), do: {:ok, state}

  def start_link(state) do
    GenServer.start_link(
      __MODULE__,
      state,
      name: __MODULE__
    )
  end
end

This works because __MODULE__ maps to an atom.

If we wanted to, we can improve our start_link/2 method to accept an atom as a name. We can then use the name variable as our pid when implementing our callbacks:

defmodule MyModule do
  use GenServer

  @impl true
  def init(state), do: {:ok, state}

  def start_link(state) do
    GenServer.start_link(
      __MODULE__,
      state,
      name: __MODULE__
    )
  end

  def perform_work(pid), do:
    GenServer.cast(pid, {:work})

  @impl true
  def handle_cast({:work}, state) do
    ## Do the thing in here!
  end
end

But since we have an atom that maps to the process identifier, we can simply invoke it like so:

{:ok, _} = MyModule.start_link(:worker, %{})
MyModule.perform_work(:worker)