I want to use String.to_existing_atom in elixir to avoid memory leaks.
This 100% works on the REPL:
iex(1)> defmodule MyModule do
...(1)> defstruct my_crazy_atom: nil
...(1)> end
{:module, MyModule,
<<70, 79, 82, ...>>,
%MyModule{my_crazy_atom: nil}}
So now the atom my_crazy_atom exists. I can verify this:
iex(2)> String.to_existing_atom "my_crazy_atom"
:my_crazy_atom
Compared to:
iex(3)> String.to_existing_atom "my_crazy_atom2"
** (ArgumentError) argument error
:erlang.binary_to_existing_atom("my_crazy_atom2", :utf8)
But I have some code that looks like this:
defmodule Broadcast.Config.File do
defstruct channel_id: nil, parser: nil
end
From a method call after starting a GenServer process, I can decode with Poison's
keys: :atoms!
or even just call
String.to_existing_atom("parser")
in the same place in the code and I get an error:
** (Mix) Could not start application broadcast: exited in:
Broadcast.Application.start(:normal, [])
** (EXIT) an exception was raised:
** (ArgumentError) argument error
:erlang.binary_to_existing_atom("parser", :utf8)
Oddly, if I instantiate the struct and inspect it, then the issue goes away!
IO.puts inspect %Broadcast.Config.File{}
String.to_existing_atom("parser")
What's going on here? Is this some kind of ordering thing?
MyModuleand then doingString.to_existing_atom("my_crazy_atom")from another function in another module.String.to_existing_atomcall? If I put it in a function and then call it, it works without me needing to create an instance of the struct. (I don't think mudasobwa's answer is right (or maybe I've misunderstood the question.))