alias, require, import
Introducción
Elixir facilita el reuso de software por medio de tres directivas: alias
, require
, e import
, veamos el detalle de cada uno de ellos.
alias
La directiva alias
permite conocer de otro modo a un módulo dado.
Imagina un módulo que usa una lista especializada en Math.List
. La directiva alias
permite referir a dicho módulo Math.List
simplemente como List
dentro de la definición de un módulo si haces:
defmodule Math.List do
end
defmodule Stats do
alias Math.List, as: List
# In the remaining module definition List expands to Math.List.
end
Pero, ¿qué pasa si dentro del módulo Stats
deseas acceder al módulo original List
que viene incluido en Elixir?, puedes acceder a dicho módulo haciendo uso del prefijo Elixir.
, de modo tal que sería Elixir.List
.
> Nota: Todos los módulos definidos en Elixir están dentro del espacio de nombres Elixir.
, tal como Elixir.String
. Sin embargo, por conveniencia, puedes omitir dicho espacio de nombres cuando los referencias.
La directiva alias
es frecuentemente usada para definir atajos. De hecho, si llamas alias
sin la opción :as
establece el alias automáticamente para que sea la última parte del nombre del módulo, por ejemplo:
alias Math.List
Es lo mismo que:
alias Math.List, as: List
Nota que alias
tiene alcance léxico, lo cual te permite definir atajos dentro de funciones específicas:
defmodule Math do
def plus(a, b) do
alias Math.List
# ...
end
def minus(a, b) do
# ...
end
end
En el ejemplo anterior, dado que estamos invocando alias
dentro de la función plus/2
, el atajo solo será válido dentro de la función plus/2
. minus/2
no se verá afectada en lo más mínimo.
Ahora vamos a explorar la directiva require
require
Elixir provee macros como un mecanismo para meta-programación (o escribir código que genera código). Los macros son expandidos en tiempo de compilación.
Las funciones públicas en los módulos son accesibles globalmente, pero si deseas usar macros, debes optar por requerir el módulo donde fueron definidos.
Integer.is_odd(3)
require Integer
Integer.is_odd(3)
En Elixir, Integer.is_odd/1
es definido como un macro para que pueda usarse en guardas. Esto significa que, para invocar Integer.is_odd/1
, necesitas primero requirir el módulo Integer
.
Nota que así como la directiva alias
, require
tiene alcance léxico.
import
Usarás import
siempre y cuando necesitas acceder a funciones o macros definidos en otros módulos sin usar el nombre completo. Nota que solo puedes importar funciones públicas, pues las funciones privadas nunca son accesibles desde el exterior.
Por ejemplo, si quieres usar varias veces la función duplicate/2
del módulo List
, puedes importarla:
import List, only: [duplicate: 2]
duplicate(:ok, 3)
Importaste solo la función duplicate
(que recibe 2 argumentos) desde List
. Sin embargo :only
es opcional, su uso es recomendado para evitar importar todas las funciones de un cierto módulo dado dentro del alcance actual. :except
también puede ser dada como opción para importar todo en un módulo exceptuando la lista de funciones.
Nota que import
también tiene alcance léxico. Esto significa que puedes importar macros o funciones específicas dentro de una definición de función:
defmodule Math do
def some_function do
import List, only: [duplicate: 2]
duplicate(:ok, 10)
end
end
En el ejemplo anterior, la función importada List.duplicate/2
es solamente visible dentro de la función específica. duplicate/2
no estará disponible en cualquier otra función en ese módulo.
Es importante menciones que al importar un módulo dado, automáticamente lo estás requiriendo (require
).
Como nota final acerca de la directiva import
, su uso generalmente se desaconseja en el lenguaje, así que cuando trabajes en tu propio código, prefiere el uso de alias
sobre import
.
Entendiendo los alias
Llegados a este punto, seguro estarás preguntándote, ¿qué es exactamente un alias en Elixir y cómo es representado?
Un alias en Elixir es un identificador que comienza con letra mayúscula, como String
, Keyword
, etc., el cual es convertido a un átomo en tiempo de compilación. Por ejemplo, el alias String
es traducido por omisión al átomo :"Elixir.String"
:
is_atom(String)
to_string(String)
:"Elixir.String" == String
Los alias expanden a átomos porque en la máquina virtual de Erlang, y en consecuencia Elixir, los módulos siempre están representados por átomos.
List.flatten([1, [2], 3])
:"Elixir.List".flatten([1, [2], 3])
Y este es el mecanismo que vas a usar para llamar módulos en Erlang:
:lists.flatten([1, [2], 3])