Suppress 'Module.function_name' is not defined or private

I am working on a library where, amongst other things, some default modules are called for Elixir’s built-in types like Tuples and Lists.

I do this in a manner similar to how Protocols are internally defined, namely to iterate over a list of {guard, modulename} and inside this function I can delegate to that other module’s implementation:

defmodule FunLand do
  defmodule Builtin do
    def __builtin__ do
      [is_tuple: FunLand.Builtin.Tuple,
       is_atom: FunLand.Builtin.Atom,
       is_list: FunLand.Builtin.List,
       is_map: FunLand.Builtin.Map,
       is_bitstring: FunLand.Builtin.BitString,
       is_integer: FunLand.Builtin.Integer,
       is_float: FunLand.Builtin.Float,
       is_function: FunLand.Builtin.Function,
       is_pid: FunLand.Builtin.PID,
       is_port: FunLand.Builtin.Port,
       is_reference: FunLand.Builtin.Reference]
    end
  end
end


# Inside one of the Behaviour-defining modules:
for {guard, module} <- FunLand.Builtin.__builtin__ do
    def map(mappable, function) when unquote(guard)(mappable) do
      unquote(module).map(mappable, function)
    end
  end

This works, but I am getting a lot of warnings, because not all of the modules inside FunLand.Builtin.__builtin__ will actually define all of the functions that are delegated to them. Things like

warning: function FunLand.Builtin.Atom.map/2 is undefined or private

These warnings are thrown during macro expansion, i.e. after the modules are compiled.

Because I use behaviours, it is impossible to check inside my behaviour-defining modules if the other module defines a certain function (doing things like Enum.member?(ModuleName.__info__(:functions), {:map, 2})) because this will result in a deadlock of modules waiting for each other’s compilation.

So, I think that the best approach here, is to silence the warning. How can this be done?

A possible solution I’ve found is to use Kernel.apply/3. This might be a little bit slower, because of the extra apply step. If there is a way to really suppress the warning I’d rather do that.

There is a mix project option for excluding modules from the output.

You can add in project/0: xref: [exclude: [MyModule]].

Example of that is in phoenix: https://github.com/phoenixframework/phoenix/blob/master/mix.exs

3 Likes