Digging Deeper

Explore Elixir in further depth.

We'll cover the following

The Code and Macro modules contain the functions that manipulate the internal representation of code.

Check the source of the Kernel module for a list of the majority of the operator macros, along with macros for things such as def, defmodule, alias, and so on. If we look at the source code, we’ll see the calling sequence for these. However, many of the bodies will be absent, because the macros are defined within the Elixir source.

Digging deep

Here’s the internal representation of a simple expression:

iex> quote do: 1 + 2
{:+, [context: Elixir, import: Kernel], [1, 2]}

It’s just a three-element tuple. In this particular case, the following is true:

  • The first element is the function (or macro).
  • The second is housekeeping metadata.
  • The third is the arguments.

We know we can evaluate this code fragment using eval_quoted, and we can save typing by leaving off the metadata:

iex> Code.eval_quoted {:+, [], [1,2]} 
{3,[]}

And now, we can start to see the promise and danger of a homoiconic language (a language in which the internal representation is expressed in the language itself). Because code is just tuples and because we can manipulate those tuples, we have the ability to rewrite the definitions of existing functions. We can create new code on the fly, and we can do it in a safe way because we can control the scope of both the changes and the access to variables.

Next, we’ll look at protocols, which are a way of adding functionality to built-in code and of integrating our code into other people’s modules.

Run the commands given in the snippets in the terminal below:

Get hands-on with 1200+ tech skills courses.