Code Injection and the Caller’s Context
Learn how macros are used for code injection.
We'll cover the following...
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