elixirintrospectionguard-clause

Introspect functions with guard clauses


Given a module having two functions with the same arity, but different guard clauses, how do I (ideally) see what those clauses are, or at least that there are two functions?

defmodule Test do
  def greet(name) when name == "foo" do
    IO.puts("Hello, bar")
  end

  def greet(name), do: IO.puts("Hello, #{name}")
end

Test.__info__(:functions) doesn't work as it only returns [greet: 1]


Solution

  • You can decompile the code of a module into "abstract code" and dig into that to get this info. Here's how you can get the clauses of each function in a module:

    module = Test
    
    {:ok, {^module, [abstract_code: {:raw_abstract_v1, abstract_code}]}} = :beam_lib.chunks(module, [:abstract_code])
    
    for {:function, _, name, arity, clauses} <- abstract_code do
      # Uncomment the next line to print the AST of the clauses.
      # IO.inspect(clauses)
      IO.inspect {name, arity, length(clauses)}
    end
    

    Output:

    {:__info__, 1, 7}
    {:greet, 1, 2}
    

    Note: This is likely private API and might change in the future versions of Erlang/OTP. The output above is on Erlang/OTP 20.