How to set first-class module dynamically?

I have a logic like this. All the modules have the same patterns in their names(Foo.Module_[NUMERIC]). Can I set the module into f more simply like: f = Foo.Module_#{id}; f.get() ?

id = 2

f = case id do
  "1" => Foo.Module_1
  "2" => Foo.Module_2
  "3" => Foo.Module_3
end

f.get()
defmodule Foo.Module_1 do
  def get(), do: SOME-LOGICS-HERE
end
defmodule Foo.Module_2 do
  def get(), do: SOME-LOGICS-HERE
end
defmodule Foo.Module_3 do
  def get(), do: SOME-LOGICS-HERE
end
1 Like

That’s a somewhat unorthodox approach, but it’s possible:

# Will raise if there's an attempt to use a number
# that doesn't have a corresponding module
mod = String.to_existing_atom("Elixir.Foo.Module_#{num}")

# Just call afterwards
mod.get()

The use of the String.to_existing_atom/1 is necessary because string to atom conversion isn’t safe in Erlang/Elixir, as atoms are not garbage collected, and filling up the atoms table is one of the ways to bring down the BEAM. Since the modules should be defined in the first place, the atoms that reference their names will already exist.

Hope it helps you :smiley:

2 Likes

It worked perfectly as I expected.
Thank you.

1 Like