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?

halfelf
  • 9,737
  • 13
  • 54
  • 63

1 Answers1

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])
lastcanal
  • 2,145
  • 14
  • 17
  • 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? – halfelf Nov 06 '12 at 03:06
  • 1
    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. – lastcanal Nov 06 '12 at 06:01
  • Can you show how this could be done for a normal elixir function. Something like `Enum.fetch`? Is there variable variables or variable functions? – CMCDragonkai Aug 03 '14 at 23:13
  • 1
    quoted_fetch = quote do: Enum.fetch([1,2,3], var!(item)); {value, binding} = Code.eval_quoted(quoted_fetch, [item: 2]) – lastcanal Aug 07 '14 at 16:51
  • 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. – lastcanal Aug 07 '14 at 16:59