Apply/3 with private functions

I have several functions defined as private to the module. In another private function in that module I want to take a string parameter and pass it to apply/3 to call one of those private functions via String.to_existing_atom/1. For instance:

defmodule Foo do 
  defp bar do 
    IO.puts("bar")
  end

  defp baz(s) do 
    apply(Foo, String.to_existing_atom(s), [])
  end
end

When I call Foo.baz("bar") I get the error Foo.bar is undefined or private. I would not have expected this since baz is in the same module. Am I doing something wrong or is this expected behavior? If so, is this something a macro would mitigate?

If you look at the erlang documentation for apply/3 it says:

Returns the result of applying Function in Module to Args. The applied function must be exported from Module.

Which explains why you see the error - dispatching starts with the Module, looks up its exported functions and then applies.

I think (but have not tested) that apply/2 may work in this case - at least the the documentation doesn’t suggest otherwise. ie: apply(String.to_existing_atom(s), [])

I will submit a PR to include the must be a public function note to Elixir’s documentation.

5 Likes

Pull request opened to update the documentation for apply/3.

4 Likes