line 1 spawns a process so its work is happening asynchronously. This means that it’s possible fore line 2 to run before the ets table is actually created.
EDIT: @nicd also points out that the ets table could also be dead, which is another great point. Basically, the ets table is only alive for an incredibly brief period of time, and it’s quite possible that your tab2list will happen before or after that time.
The process you spawned is the owner of the ETS table. When the process ends (right after it created the table), the table will be deleted. You will need to keep a GenServer that keeps the table alive or transfer ownership to another process. You can also set an heir that inherits the table when the owning process dies.
What others said, also if you want to just have a stupid simple global ETS table that lives as long as your VM lives here’s how to do that (don’t do that in production though):
defp get_table() do
if :ets.info(@table) == :undefined do
:ets.new(@table, [:public, :named_table])
:ets.give_away(@table, get_lively_pid(), nil)
# avoid races
Process.sleep(5)
@table
else
@table
end
end
defp get_lively_pid() do
spawn(fn -> Process.sleep(:infinity) end)
end
you can then do stuff like :ets.first(get_table()) etc.
There are many wonderful suggestions but I’m curious why you need this ets table accessible from multiple processes. It sounds like using ets as a gasp global variable.
ets doesn’t support transactions, does read/write collisions matter ? Data in ets doesn’t survive a reboot nor is it distributed. Are these something you need ?
Usually after some prodding we realize that mnesia is a better fit.
Thank you all for your answers, I thought “:public” would be enough / I mixed access and process ownership.
As for why use ETS here, it is to do some RAM prefetching, before assembling data, in some context where transactions are not needed (this isn’t live data and data is heavily partitionned) so I think ETS is a good fit. It would also be a bit faster than in-memory Mnesia.