ETS named table name vs process name - Whats the difference?

I’m learning about ETS tables, and I’m a bit confused about how ETS tables are named. Consider the following code:

defmodule EtsKeyValueStore do
  use GenServer

  def init(_) do
    :ets.new(
      __MODULE__,
      [:named_table, :public, write_concurrency: true]
    )

    {:ok, nil}
  end

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

This code works just fine, but it is confusing to me that EtsKeyValueStore process and the ETS table it self are both registered under the same name.

How it could be? What is the difference between both names? How the system know if I’m talking about the EtsKeyValueStore process or ETS table?

Keep in mind that __MODULE__ is just an atom. It’s a syntactic sugar for the current module (so that if you refactor your life is easier), nothing more special than that. You could name the ets table :foo, if you wanted to. And you could name the process :bar. You could also drop in a second ets table with some other name. Names are just names.

The ets tables will never be confused with the process genserver calls, because you have to use the :ets functions to access them. And you’ll use GenServer functions to refer to the names genserver. So no confusion! An atom is just a fancy, universal enum.

3 Likes

I get that names are just atoms, but when I give a name to a process, the BEAM has to keep track of it in somewhere right? Some kind of map, to link atoms and pids like:

%{
first_process_name: #PID<0.200.0>, 
second_process_name: #PID<0.201.0>, 
first_ets_table: #PID<0.202.0> 
}

For example, I can’t register two processes with the same name, neither 2 ets tables with the same name. But I can register a process with the same name as a ets table, why?

Conceiveng them as k/v stores is reasonable: Think of them as just different k/v stores (or namespaces). Just as you can have two different map values that don’t interfere with each other.

map1 = %{foo: :bar}
map2 = %{foo: :baz}
map1[:foo] # ==> :bar, writing to map2 did not affect map1

I should clarify that there should be no confusion on the BEAM side. Of course if you give them the same name it is possible to get your own head turned upside down with whether you are talking about the ets table or the process. (I have done this), so unless you really need to name the GenServer, just let it slide namelessly into the night. To avoid this often I have ets tables where the GenServer literally does nothing but hibernate after creating the table.

2 Likes

Technically, the list of functions one might use with the Process.dest() is not limited to GenServer.

E. g. one might send/2 a message to the process.

1 Like