...

/

Code Injection and the Caller’s Context

Code Injection and the Caller’s Context

Learn how macros are used for code injection.

Macros don’t just generate code for the caller, they inject it.

The place where code is injected is called a context. A context is the scope of the caller’s bindings, imports, and aliases. To the caller of a macro, the context is precious. It holds the view of the world, and by immutability, we don’t expect our variables, imports, and aliases to change underneath us.

Elixir macros strike an excellent balance to safeguard our context while allowing explicit access where necessary. Let’s see how to inject code safely and the available tools to reach into the caller’s context when necessary.

Injecting code

We have to understand the two contexts in which a macro executes, or we risk generating code in the wrong place. The contexts are:

  • Context of the macro definition.
  • Caller’s invocation of the macro.

Let’s see these contexts in action by defining a definfo macro that prints a module’s information in a friendly format while showing the context the code executes in.

defmodule Mod do
  defmacro definfo do
    IO.puts "In macro's context (#{__MODULE__})." 

    quote do
      IO.puts "In caller's context (#{__MODULE__})." 

      def friendly_info do
        IO.puts """
        My name is #{__MODULE__}
        My functions are #{inspect __info__(:functions)}
        """
      end
    end
  end
end

defmodule MyModule do
  require Mod
  Mod.definfo
end
A Mod module with definfo macro that prints a module’s information in a friendly format.
...