Welcome to a tutorial on Aliases in Elixir.
To facilitate software reuse, three directives (i.e alias, require, and import) are provided by Elixir. Also, Elixir provides a macro called use, as shown below.
# Alias the module so it can be called as Bar instead of Foo.Bar
alias Foo.Bar, as: Bar
# Ensure the module is compiled and available (usually for macros)
require Foo
# Import functions from Foo so they can be called without the `Foo.` prefix
import Foo
# Invokes the custom code defined in Foo as an extension point
use Foo
This directive allows one to set up aliases for any given module name. For instance, if you want to give an alias 'Str' to the String module, you can do that by simply writing the code below:
alias String, as: Str
IO.puts(Str.length("Hello"))
The output is:
5
In Elixir, an alias is given to the String module as Str. So, when we call any function using the Str literal, it typically references the String module. Interesting, this is helpful, especially, when we use very long module names and want to substitute those with shorter ones in the current scope.
Note that, Aliases MUST start with a capital letter.
Thus, aliases are valid only within the lexical scope they are called in. For instance, if you have two modules in a file and make an alias within one of the modules, that alias will not be accessible in the second module.
Now, when you give the name of an in-built module, such as a String or a Tuple, as an alias to some other module, you will need to prepend it with "Elixir" in order to access the inbuilt module. Check out the example below.
alias List, as: String
#Now when we use String we are actually using List.
#To use the string module:
IO.puts(Elixir.String.length("Hello"))
The output is:
5
Elixir provides macros as a mechanism for meta-programming, that is writing code that generates code.
By common definition, Macros are chunks of code that are executed and expanded at compilation time, meaning that for you to use a macro, you need to guarantee that its module and implementation are available during compilation. The require directive is used to do that.
Integer.is_odd(3)
If we run the above program, it will generate the result below:
** (CompileError) iex:1: An integer must be required before invoking the macro Integer.is_odd/1
Integer.is_odd is defined as a macro in Elixir. Thus this macro can be used as a guard, meaning that, in order to invoke Integer.is_odd, the integer module is needed.
Use the required Integer function and run the code as shown below.
require Integer
Integer.is_odd(3)
The code above when run will produce this output.
true.
Generally, a module is not required before usage, except we want to use the macros available in that module. An attempt to call a macro that was not loaded will raise an error.
Note: Just like the alias directive, require is also lexically scoped. More on the macro will be discussed in a subsequent tutorial.
The import directive is used to easily access functions or macros from other modules without using the fully-qualified name. for example, if we want to use the duplicate function from the List module several times, we can simply import it, as shown below.
import List, only: [duplicate: 2]
In the above case, we are importing only the function duplicate (with argument list length 2) from List. However, :only is optional, because its usage is recommended in order to avoid importing all the functions of a given module inside the namespace. Whereas, :except could be given as an option in order to import everything in a module except a list of functions.
Also, the import directive supports :macros and :functions to be given to :only. E.g. to import all macros, a user can write this code:
import Integer, only: :macros
Note: Import to is Lexically scoped quite like the require and the alias directives. Also, know that 'importing a module also 'require's it.
the use is not a directive but is a macro that is tightly related to require and allows you to use a module in the current context. The use macro is frequently used by developers to bring external functionality into the current lexical scope, usually modules. Check out the example below:
defmodule Example do
use Feature, option: :value
end
use is a simple macro that transforms the above into:
defmodule Example do
require Feature
Feature.__using__(option: :value)
end
At first, the use Module requires the module and then calls the __using__ macro on Module. Elixir language has great metaprogramming capabilities and it has macros to generate code at compile time. The __using__ macro is called in the above instance, while the code is injected into our local context, and the local context is where the use macro was called at the time of compilation.