Namespaces in Elixir (and how to change namespaces)?

I’m curious if there is an official link for how Elixir apps define namespaces? I’m used to PHP PSR-0 or PSR-4 that basically defines the convention to be used between class names and their location within the file structure.

From my tire-kicking so far, it’s clear that Elixir module names must start with a capital letter, and the dot separators in the module names correspond to directories. Single-word CamelCase gets translated to all lowercase snake_case in the file names. Are there any other rules or customizations here?

And importantly… how does one painlessly change an app or namespace name? My current IDE (IntelliJ IDEA) seems to have no awareness of the namespaces, so changing them after the fact is essentially a manual process (and thus highly vulnerable to human error). Many of the errors I’ve encountered so far while learning Elixir stemmed from a simple misspelling of the class or file name.

Any thoughts or recommendation on this? Thanks!

There are no “namespaces” in Elixir.

What you are seeing is convention, not rule. A module’s name may contain a “.” and the convention is to use that dot to establish a hierarchical structure. That convention is supported in macros that are part of the core language like alias.

The format of the files on disk are not enforced in any way. As you point out, there are conventions which people follow to make it easier for others to navigate their projects.

3 Likes

The module name should be an atom. Period. :foobar is perfectly valid module name.

Also, I doubt I understand how any IDE magic might be less error-prone than sed.

To be fair, IntelliJ holds a massive load of references between classes and whatnot so that it can effectively enumerate all of them at will and thus also rename literally all of them in other languages. It’s perhaps the one true feature of IntelliJ that really won’t ever make it to simple editors.

sed does not move altered files to a new location.

Interesting… thanks @easco … if the module names are only a convention, what (if any) rules guide the relationship between a module name and its file name? When Elixir encounters a module name (e.g. within some other module), how does it know where to find the corresponding file on disk? Does it just scan any and all directories for any .ex files at compile time?

@mudasobwa sed and grep are great, but convenience is hugely important and a good IDE is especially valuable in guiding newcomers along the recommended paths. I can only speak from experience – I coded in Vim for many years and it was only when I upgraded to dedicated IDEs that my understanding, debugging, formatting, and testing skills really locked into place. Anyhow, that’s a whole other topic… as far as this thread is concerned, I don’t see any options in IDEA for refactoring existing projects to do something as simple as changing the app’s name.

Interesting reads which might answer your questions:

2 Likes

The Elixir Style Guide has some information on best practices around “namespacing”.

In Elixir a file may contain zero to many modules, and their names need not match the file name.

If there is no module, compiling a file executes its contents but produces no .beam files.

When an .ex file has one or more modules the compiler emits one separate .beam file for each module, and the file name of the .beam file does match the name of the corresponding module. The name of the file that stores the Elixir source code is irrelevant.

The VM is the one that requires matching names for .beam files and the modules they define.

3 Likes

Thank you for the detailed explanation. So just to make sure I’m following (since this quite a departure from the world of PHP autoloading), when you compile a project (e.g. by running mix phx.server), then mix scans the directory contents for any .ex files – any modules inside those files are parsed and a separate .beam file is created for each module. So the end result of this is that we can use any file names that we want and any module names that we want, but the recommended convention is the one described in the style-guide linked by @anthonator – is that more or less correct? There’s no problem with run-time autoloading (like there is with PHP) because the directories are scanned at compile time.

1 Like

Exactly!

Mix generates the .beam files under _build/{env}/lib/{app}/ebin. You’ll see there that in particular the directory structure is gone. Since module names are atoms, and they have to match their file name, you’ll find a flat directory with things like Elixir.AppWeb.Endpoint.beam.

You can experiment easily with this using elixirc directly, to remove the tooling layer. If you define a module Bar in a file caled foo.ex and compile the file with elixirc foo.ex, you’ll find Elixir.Bar.beam is generated in the current directory.

5 Likes