How to call a method dynamically in Elixir, by specifying both module and method name?
You can use apply/3
which is just a wrapper around :erlang.apply/3
. It simply invokes the given function
from the module
with an array of arguments
. Since you are passing arguments as the module and function names you can use variables.
apply(:lists, :nth, [1, [1,2,3]])
apply(module_name, method_name, [1, array])
If you want to understand more about how elixir handles function calls (and everything else) you should take a look at quote
and unquote
.
contents = quote do: unquote(module_name).unquote(method_name)(1, unquote(array))
which returns the homoiconic representation of the function call.
{{:.,0,[:lists,:nth]},0,[1,[1,2,3]]}
You can unquote
the quoted function call with Code.eval_quoted/3
{value, binding} = Code.eval_quoted(contents)
Edit: here is an example using Enum.fetch along with a var.
quoted_fetch = quote do: Enum.fetch([1,2,3], var!(item));
{value, binding} = Code.eval_quoted(quoted_fetch, [item: 2])
Related videos on Youtube
halfelf
Hardcore PC/Board/TRPG Gamer, Poet, Ruby/Erlang/Clojure Fan. Now works at http://www.nautiluscapital.net My start up: https://aimeike.tv https://duomu.tv
Updated on July 09, 2022Comments
-
halfelf over 1 year
I'd like to know what exactly a method name is in elixir:
array = [1,2,3] module_name = :lists method_name = :nth # this not working module_name.method_name(1, array) # error, undef function lists.method_name/2 module_name.nth(1, array) # returns 1, module_name is OK. It's an atom
But I can do almost the same thing in erlang:
A = [1,2,3]. X = lists. Y = nth. X:Y(1,A). # returns 1
How can I do this in elixir?
-
halfelf over 11 yearsGood. So the method name is a atom. Now I think it is just the syntax which don't allow us writing
module.method
in elixir, right? -
lastcanal over 11 yearsI believe you are correct. I think the only way to make this work would be to change the syntax to use atoms when calling module functions (i.e.
:lists.:nth
). I'd rather just use apply in cases like this. -
halfelf over 11 yearsThanks. This answer is very helpful.
-
CMCDragonkai over 9 yearsCan you show how this could be done for a normal elixir function. Something like
Enum.fetch
? Is there variable variables or variable functions? -
lastcanal over 9 yearsquoted_fetch = quote do: Enum.fetch([1,2,3], var!(item)); {value, binding} = Code.eval_quoted(quoted_fetch, [item: 2])
-
lastcanal over 9 yearsI've updated the answer for better formatting. Using var!/1 allows you to substitute a variable inside a quoted method for the value of the corresponding key in the binding.