Elixir no solo es conocido por su modelo de concurrencia y eficiencia, sino también por su poderosa capacidad de metaprogramación, gracias a sus macros. Con ellas, puedes escribir código que genera más código, permitiendo crear herramientas, DSLs (lenguajes específicos de dominio) y extender el lenguaje.
En Elixir, las macros son funciones especiales que reciben expresiones y devuelven otras expresiones transformadas. Estas transformaciones ocurren en tiempo de compilación, lo que las diferencia de las funciones normales.
defmodule EjemploMacro do
defmacro saludo do
quote do
IO.puts("¡Hola, mundo!")
end
end
end
require EjemploMacro
EjemploMacro.saludo()
# Salida: ¡Hola, mundo!
¿Cómo funciona esto?
- quote/2: Captura código como datos. Convierte un bloque en su representación AST (Abstract Syntax Tree).
- unquote/1: Inserta valores dinámicos en el código generado.
- defmacro: Declara macros.
Imagina que necesitas loguear todas las llamadas a funciones en un módulo. Con macros, puedes automatizar este proceso:
defmodule LoggerMacro do
defmacro log_call(fun_name, do: block) do
quote do
IO.puts("Llamando a #{unquote(fun_name)}")
result = unquote(block)
IO.puts("Resultado: #{result}")
result
end
end
end
defmodule Ejemplo do
require LoggerMacro
def calcular do
LoggerMacro.log_call(:calcular) do
1 + 2
end
end
end
Ejemplo.calcular()
# Salida:
# Llamando a calcular
# Resultado: 3
Los macros son herramientas poderosas para crear DSLs. Por ejemplo, un DSL para rutas web (similar a Plug.Router):
defmodule MiniRouter do
defmacro route(method, path, do: block) do
quote do
def handle_request(unquote(method), unquote(path)) do
unquote(block)
end
end
end
end
defmodule MyRouter do
require MiniRouter
MiniRouter.route(:get, "/") do
IO.puts("¡Bienvenido!")
end
MiniRouter.route(:post, "/create") do
IO.puts("¡Creando recurso!")
end
end
MyRouter.handle_request(:get, "/")
# Salida: ¡Bienvenido!
Aunque las macros son útiles, pueden complicar el código:
- Usa macros solo si la lógica no puede resolverse con funciones.
- Opta por composición funcional siempre que sea posible.
Las macros en Elixir son una herramienta increíblemente poderosa para extender el lenguaje y crear soluciones elegantes. Sin embargo, requieren un buen entendimiento del AST y un uso responsable.