TheBeast2001

TheBeast2001

Why do we use macros in elixir?

I have seen macros being used in a lot of code at different parts but never really understood the thought process behind it. Can someone please list some examples with some thought process behind using macro ?

Most Liked

sabiwara

sabiwara

Elixir Core Team

First thing to mention is when NOT to use a macro, that is, almost always. You only want to reach for a macro when you have no choice but to use one. See Library Guidelines — Elixir v1.15.5

There are several reasons you might need a macro, but almost all of them are for libraries, not your typical application code:

  • you need to do something at compile time, e.g. defining a function (defn in Nx, Plug.Router…), which regular functions cannot do

  • you want a specific DSL like Ecto.Query

  • you want a syntax to generate a data structure that also works in patterns/guards (../2 for ranges, Date/Time sigils like ~D…). You can do a..b = 1..10, but functions cannot be called in patterns/guards.

  • you need to access the AST, e.g. assert/1: if it was a function, it would only see the final value (false), not the operation you’re trying to do (>, ==…), the operands (left and right), or the code it is printing (code: assert 1 + 2 + 3 + 4 > 15).

  • performance/optimization: Logger could typically be implemented with functions, but we want to only evaluate the message if the logger level is above the configured level, and an API like Logger.maybe_info(fn -> "hello #{world}" end) would have a bigger runtime footprint (plus a more clunky API). Instead, we generate efficient code by checking the log level at compile time.

18
Post #5
Marcus

Marcus

For an example the if/2 in Elixir is a macro that expands to a case/2. You can see this if you disassemble the code from the BEAM file.

# macro.exs
Mix.install([{:beam_file, "~> 0.5.3"}])

defmodule Foo do
  def pos(x) do
    if x > 0 do
      "yes"
    else
      "no"
    end
  end
end
|> BeamFile.elixir_code!()
|> IO.iodata_to_binary()
|> IO.puts()
> elixir macro.exs
defmodule Elixir.Foo do
  def pos(x) do
    case :erlang.>(x, 0) do
      false -> "no"
      true -> "yes"
    end
  end
end
odix67

odix67

a good entry point is here Macros - The Elixir programming language, but also point 1 and 3 of the meta programming section

D4no0

D4no0

Not necessarily. Modeling things in terms of offloading business validations and having custom rules at compile-time is extremely powerful and can make code that is complex from business side into a delight to work on by application developers.

Not sure I agree with that. I’ve created in quite a few projects DSLs that subsequent developers would use successfully to write business logic in an easy manner. I hope to show more examples in the future as this is a topic that comes around from 90s and it is a very powerful concept, but it can be used only in languages that support metaprogramming.

I would say that the biggest problem now with writing a lot of macros and using metaprogramming is how wild this field is at the moment, it’s extremely powerful but at the same time it requires a better abstraction for specific things. I think that libraries like Spark are a great step into the right direction on abstracting and making easier to use the power of metaprogramming without going into its complexity, but still require a lot of experimenting.

LostKobrakai

LostKobrakai

Abstractions should be modeled with modules and functions though.

Macros don’t help with abstraction. Macros cannot do what you cannot manually write out as well - by definition. So macros are always optional. They do however allow you to write less code manually by using code generation to let the computer create the boilerplate portion of the desired code.

That doesn’t mean you cannot use macros in your own codebase. But I also wouldn’t call them “typical application code”. Besides code needing to be a macro to interact with a macro of a library (e.g. ecto fragments, stuff around heex, stuff around verified routes, …) truely custom to an application macros in my experience are rare.

Where Next?

Popular in Questions Top

shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
Exadra37
Sometimes I want to check if the input into a function is not a blank string. My first approach: defmodule Example do def do_stuff(s...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

Other popular topics Top

sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New

We're in Beta

About us Mission Statement