Sometimes we need to generate some module names dynamically, and then call the functions inside it. But what we often meet is clearly have that module, the result is still raise module undefined ...
Let's see what's going on here.
First we define a function
IEX (1) > defmoduledo ... (1) > defdo ... (1) > x + y ... (end... (End
When we normally call it yes, there is no problem:
IEX (2) > Science.Math.add 1,23
But
IEX (3) > t= "Science.math" "Science.math"IEX (4) >: "Science.math". Add (1, 2)* * ( Undefinedfunctionerror) undefined function: "Science.math". ADD/2 (module: "Science.math" is not available) : " Science.math ". Add (1, 2)
Why did the module not find it?
Because we define the module should be: "Elixir.Science.Math", instead of: "Science.math"
So we should use
IEX (5) > (t|> string.split (".") |> Module.concat). Add (3)
But the module does the conversion of string to atom using: Erlang.binary_to_atom (String,: UTF8)
A large number of calls to this function during runtime can result in an atomic number being exhausted (the atom of Erlang is not recycled)
So we can also use MODULE.SAFE_CONCAT/1
IEX (5) > (t|> string.split (".") |> Module.safe_concat). Add (3)
Used by Safe_concat: Erlang. Binary_to_existing_atom (String, :UTF8).
This solves the risk of the above function, but also introduces the possibility that the input string is a system that has never exist atom will be crash off.
If we just want to invoke the function inside the "Nested.Foo.Test" module, we can use it in a clever way.
IEX (6) > t = "Science.math" "Science.math"IEX (7) >: "Elixir.#{t}". Add 3
The last method is tentative, but the solution you choose should be the best Module.safe_concat,
If your needs are really likely to enter a module that never exist, you should use Module.concat, but you want a way to ensure that atom does not run out.
Let's take a look back at the front @moduledoc of module
during compilation time. It allows a developer to dynamically add, delete and register Attributes,attach documentation and so forth. After a module was compiled, using many of the functions in this module willraise errors, since it was out of their scope to Inspect runtime data. Most ofthe runtime data can be inspected via the __info__ (attr) function attached Toeach compiled module.
It was not meant to solve the problem during the run ....
[Elixir008] Dynamic function call mode in Nested module