Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Elixir support introspection to show function origins?

Tags:

elixir

If a module imports multiple other modules, it may not be obvious where a given function came from. For example:

defmodule Aimable do
  import Camera
  import Gun

  def trigger do
    shoot # which import brought it in?
  end
end

I know there are ways to minimize this kind of confusion: good naming, focused modules, targeted imports like import Gun, only: [:shoot], etc.

But if I come across code like this, is there a way to inspect Aimable and see the origins of the function shoot?

like image 960
Nathan Long Avatar asked Dec 17 '15 01:12

Nathan Long


2 Answers

You can do this directly:

# from inside the module; IO.inspect(&Aimable.shoot/0) reveals nothing
IO.inspect &shoot/0 #=> &Gun.shoot/0

Check this out

Also remember that you cannot have same function names with same arity in two different modules and import them both in another module. This will result in ambiguity error when calling that function.

Another painful way. You can use function_exported?/3.. Specs:

function_exported?(atom | tuple, atom, arity) :: boolean

Returns true if the module is loaded and contains a public function with the given arity, otherwise false.

Examples:

function_exported?(Gun,    :shoot, 0) #=> true
function_exported?(Camera, :shoot, 0) #=> false
like image 85
coderVishal Avatar answered Sep 20 '22 10:09

coderVishal


Use __ENV__

As I learned on another question, the __ENV__ macros gives access to various environment info, including __ENV__.functions and __ENV__.macros.

__ENV__.functions returns a list of tuples of modules and the list of functions they provide, like:

[{Some.module, [do_stuff: 2]}, {Other.Module, [a_function: 2, a_function: 3]}]

You could visually scan this for shoot, or write code to search through it.

like image 32
Nathan Long Avatar answered Sep 20 '22 10:09

Nathan Long