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)> 
 
2
Kudos
 
2
Kudos

Now read this

The horrors of package formats, in Rust!

Flat files # Do I even need to say anything here? Horrible choice of package format, unless you’re distributing one file. Tarballs # As far as I can tell, the tar crate can only unpack to a real directory on the filesystem, because... Continue →