47

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?

1 Answer 1

67

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])
Sign up to request clarification or add additional context in comments.

5 Comments

Good. 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?
I 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.
Can you show how this could be done for a normal elixir function. Something like Enum.fetch? Is there variable variables or variable functions?
quoted_fetch = quote do: Enum.fetch([1,2,3], var!(item)); {value, binding} = Code.eval_quoted(quoted_fetch, [item: 2])
I'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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.