Elixir dotted namespacing is not sophisticated. As in Erlang, a module name is just an atom
. A namespaced module name like Nesting.Nested
is really just an alias to the atom :"Elixir.Nesting.Nested"
; the namespacing is a convention rather than something built into the language.
One exception is the teaspoon of syntactic sugar that sweetens defining a module within a module.
defmodule Nesting do
defmodule Nested do
# The Nested module is really Nesting.Nested
def inner_hello, do: :inner_hello
end
# There is an implicit
# alias Nesting.Nested here
def outer_to_inner_hello, do: Nested.inner_hello()
end
The sugar has given us the automatic "namespacing" of Nested
and the implicit alias of Nesting.Nested
to Nested
within the rest of the module.
This is all documented. It is also the extent of the sugar: the code below does not compile.
defmodule Deep.Nesting do
def outer, do: :outer
defmodule Nested do
# WILL NOT COMPILE: Deep.Nesting would need to be directly
# referenced or aliased
def inner_outer, do: Nesting.outer()
# ALSO INVALID. We would not really expect
# Deep.Nesting functions to be imported
def inner_outer2, do: outer()
end
end
Ok, I lied. There are some other surprising aspects to nested modules:
- While the outer module's functions are not imported to the inner, any imports to the outer module are also available to the inner one.
- While the outer module is not implicitly aliased in the inner module, any modules aliased in the outer module are also aliased in the inner.
defmodule Namespace.InNamespace do
def a_thing, do: :thing
end
defmodule Nesting do
alias Namespace.InNamespace
import Enum, only: [map: 2]
defmodule Nested do
# Enum import is available
def inner_map, do: map([1, 2, 3], &(&1 * 2))
# Alias also available
def inner_thing, do: InNamespace.a_thing()
end
end
I can not find this behaviour documented anywhere but it may be worth knowing, especially if trying to figure out import or alias clashes.
Update - 2018-11-16
José Valim has pointed out that the behaviour is (sort of) documented:
... we say that alias, import and require are lexical ... At the moment they are defined, everything below the declaration in the same code branch will have the same aliases, imports, etc
The documentation is here.