Dynamic function “definitions” in Elixir
This is more of a dumb hack than anything, I just happened to learn about this today.
Suppose that you’re writing a shell-command executing library. You can, of course, always use System.cmd/3
to do so. However, what if you wanted to make a cool interface like MyModule.echo "test"
or MyModule.program_name :banana
? Well, it turns out you can just do this:
defmodule Test do
def unquote(:"$handle_undefined_function")(function_name, function_args) do
# Process things here!
end
end
and suddenly you have magic “dynamic function definitions”!
-> iex
Erlang/OTP 23 [erts-11.1.2] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [hipe]
Interactive Elixir (1.11.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> defmodule Test do
...(1)> def unquote(:"$handle_undefined_function")(function_name, function_args) do
...(1)> IO.inspect function_name
...(1)> IO.inspect function_args
...(1)> :ok
...(1)> end
...(1)> end
{:module, Test,
<<70, 79, 82, 49, 0, 0, 5, 164, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 178,
0, 0, 0, 17, 11, 69, 108, 105, 120, 105, 114, 46, 84, 101, 115, 116, 8, 95,
95, 105, 110, 102, 111, 95, 95, 10, 97, ...>>,
{:"$handle_undefined_function", 2}}
iex(2)> Test.undefined
:undefined
[]
:ok
iex(3)> Test.this_is_a_test 1, 2, 3, 4, 5
:this_is_a_test
[1, 2, 3, 4, 5]
:ok
iex(4)> Test.echo "hello world!"
:echo
["hello world!"]
:ok
iex(5)>