$handle_undefined_function in Elixir/Erlang
I was searching for ways to implement Ruby's method_missing in
Elixir the other day. Then I ran into this package:
andrewvy/method_missing: Elixir Library for dynamic code
execution. And it implements exactly what I want: a method_missing
function to dynamically generate function body for what's not defined
yet.
defmodule Dog do
use MethodMissing
def method_missing(func, _args) do
func_name = Atom.to_string(func)
cond do
Regex.match?(~r/bark|woof/, func_name) -> "WOOF"
true -> "?"
end
end
end
Dog.bark()
# > "WOOF"
Dog.woof()
# > "WOOF"
Dog.meow()
# > "?"
I was curious about how it was implemented in Elixir, so I looked into
the lib directory. Surprisingly, it's fairly simple:
defmodule MethodMissing do
defmacro __using__(_opts) do
quote do
def method_missing(_func, _args) do
end
def unquote(:"$handle_undefined_function")(func, args), do: method_missing(func, args)
defoverridable method_missing: 2
end
end
end
From this implementation, we can know that we don't even need to use
this package to get method_missing in Elixir. (The name
method_missing is not very functional either.)
All we need to do is to define $handle_undefined_function/2. And
just like method_missing, it will receive two arguments, one for the
function name, and one for the list of arguments.
Again, I want to praise Elixir/Erlang when I discovered this feature. Almost every time I miss something in Ruby, Elixir already has a solution for that.
Although, I doubt that $handle_undefined_function will be as popular
in the Elixir community as method_missing in the Ruby community.
Elixir is a language that emphasize on explicity.
Looking for behaviors that are hidden under
$handle_undefined_functionis a long trip.This kind of meta-programming would always be the last resort for an Elixir developer.
$handle_undefined_functionmight not be as efficient asmethod_missingWhen we use
method_missing, we usually usedefine_methodto speed up future method calls.But Elixir, as a compiled language, doesn't have a function like
define_methodto generate new functions. So it may be much slower.
After all, I'm very glad that Elixir/Erlang provide us an option to do this kind of meta-programming. And I can't wait to see more surprises Elixir/Erlang bring to me in the future.