---
title: "Understanding Elixir's Strange Module Names"
published: "2019-01-30"
publisher: Honeybadger
author: Starr Horne
category: Elixir articles
tags:
  - Elixir
description: "While brushing up on Elixir for our company hackathon, I discovered that it's way of resolving modules is a little strange. In this post I dive into the strangeness to reveal the underlying mechanisms."
url: "https://www.honeybadger.io/blog/elixir-module-names/"
---

Last week was amazing. It was our first ever Honeybadger Hack Week. We got to take a momentary break from thinking about exceptions and uptime to focus all our energies on something completely new. We decided as a team to build a small app in Elixir and Phoenix.

As I was getting comfortable with Elixir, one weird thing began to stand out to me. When you open up the console (iex) and type in a module name, there's never an error. Even when the module doesn't exist.

```
iex> SomeModule # => SomeModule
```

This is unlike Ruby, where you'll always get an error:

```
irb> SomeClass NameError: uninitialized constant SomeClass
```

It turns out, Elixir handles module names in an unexpected way. It's a little strange, but once you understand the underlying mechanism, it becomes very easy to reason about modules.

So pull up a seat. Gather round the fire and let me tell you a story.

## How other languages handle modules

In static languages like Rust, modules only really exist at compile-time. They're used to perform correctness checks, but then they're discarded and aren't present in the compiled object file except perhaps as debug metadata.

```rust
mod sound { fn guitar() { } } sound::guitar();
```

In Ruby, modules and classes are special kinds of objects. Module "names" are just variables. They have special `CamelCase` names, and some special lookup rules, but they're basically just variables. You can even reassign them.

```ruby
module MyModule def self.hello() puts "world" end end YourModule = MyModule MyModule = nil YourModule.hello # => "world"
```

## Elixir's surprising approach

At first glance, Elixir looks like Ruby. We can define modules, assign them to variables then call functions as if we were referencing the original.

```elixir
defmodule MyModule do def hello() do IO.puts("world") end end x = MyModule x.hello() # => "world"
```

But there _is_ a difference.

If you're _really_ paying attention you may have noticed that in the ruby example, we have `YourModule = MyModule`, while in elixir, we have `x = MyModule`. That's because elixir gives an error if I try the former:

```elixir
YourModule = MyModule # ** (MatchError) no match of right hand side value: MyModule
```

I can assign a module name to a variable, but the module name itself doesn't seem to be a variable like it is in Ruby. Instead, module names are "atoms."

## Atoms

Atoms are used to name things when you don't want the overhead of using a string. They're very similar to Ruby's "symbols":

```elixir
:foo :bar :"this atom has spaces and.special.chars"
```

Common uses for atoms are as keys in maps (hashes in Ruby, objects in JavaScript) and to specify keyword arguments in functions:

```elixir
my_map = %{foo: 1} my_func(foo: 1)
```

They're also used to name modules. For example, if I want to call Erlang's `format` function from elixir, I would write something like this:

```elixir
:io.format(arg1, arg2)
```

Like all Erlang modules, we reference the `io` module via an atom, `:io`.

## Aliases

At this point I imagine you're thinking, "Wait a second! Elixir module names look like `MyModule` not `:my_module`! Those aren't the same!"

That's because Elixir is playing tricks on us. Behind the scenes, it converts any code referring to `MyModule` to refer to the atom, `:"Elixir.MyModule"` . You can see this in action if you open up iex:

```elixir
MyModule == :"Elixir.MyModule" # true
```

The substitution of module name like `MyModule` with an atom is called "aliasing." It happens automatically for any keyword that looks like a module name: `AnythingThatLooksLikeThis`.

The reason that we reference Erlang modules directly with atom (`:io`, etc) is because there's no aliasing involved. Though, if you wanted to you could manually create an alias:

```elixir
alias :io, as: IO IO # => :io
```

## Practical Implications

Now that we know that "module names" in Elixir are just atoms + aliasing, it's easy to reason about modules.

First, we see why we got an error when we tried to assign `YourModule = MyModule`. When expanded, that code becomes:

```elixir
:"Elixir.YourModule" = :"Elixir.MyModule" # error
```

Assigning one atom to another makes no sense. You might as well try to say `1 = 2` or `"foo" = "bar"`.

Furthermore, we see that anything that can be done with an atom can also be done with a module name:

```elixir
# Call functions using the atom directly :"Elixir.MyModule".hello() # Construct module names from strings, dynamically. # Probably not a best practice. String.to_atom("Elixir.MyModule").hello() # Pass a module into an anonymous function (fn x -> x.hello() end).(MyModule) # Make a genserver name equal the current module name GenServer.start_link(Stack, [:hello], name: __MODULE__) # Execute the same function in a list of modules for mod <- [MyModule, OtherModule], do: mod.hello() # Reference a module before it's defined. Just don't run this function if it isn't :) def do_something(), do: SomeOtherModule.something()
```

## Conclusion

When I first discovered the use of atoms for elixir modules, I wasn't thrilled. It seemed ugly and weird. But I've come around.

Atoms are perfect for naming things, including modules. They're fast. They're never garbage-collected. They're unique. And best of all, they're easy to reason about. Like a lot of Erlang, they make a lot of sense once you get over the intitial strangeness.

---

## Try Honeybadger for FREE

Intelligent logging, error tracking, and Just Enough APM™ in one dev-friendly platform. Find and fix problems before users notice.

[Start free trial](https://app.honeybadger.io/users/sign_up)

[See plans and pricing](https://www.honeybadger.io/plans/)
