1
votes

I have following code snippet:

defmodule Play do

  defmacro mobile(expr) do

    IO.puts "I will compile"

    quote do
      IO.puts "#{inspect unquote(expr)}"
      unquote(expr)
    end

  end

end

defmodule Run do
  import Play

  def run do
    IO.puts "Execute macro"
    mobile(2+2)
  end
end

When I compile this file, I've got following output

iex(46)> c "playground.exs"
I will compile
[Run, Play]

As you can see, elixir compiles macro but quote block is untouched. So when I run following code snippet:

iex(47)> import Run
nil
iex(48)> Run.run
Execute macro
4
4

The quote expression in macro is going to executed, as expected.

Now I remove the run module

defmodule Play do

  defmacro mobile(expr) do

    IO.puts "I will compile"

    quote do
      IO.puts "#{inspect unquote(expr)}"
      unquote(expr)
    end

  end

end

Compiles the file

iex(49)> c "playground.exs"
playground.exs:1: warning: redefining module Play
[Play]

Where is here the text I will compile?

And later, import the module

iex(50)> import Play
nil

execute it

iex(51)> Play.mobile 2 + 2
I will compile
4
4

And voila the text appears.

What is the difference, when I import a macro into a module and import into shell? Why I did not get the text I will compile one the second example?

1

1 Answers

2
votes

The macro isn't executed when the module defining it (Play) is compiled. It's executed when a module that calls it is compiled. You'll only see "I will compile" when the macro is executed, so it should probably say "I will execute."

In your first example, the macro is executed when the Run module is compiled.

In your second example, the macro is executed when the repl compiles the line of code you gave it.

You could further verify this for yourself if you split your Run module out into its own file. Compile Play and then compile Run and see when you get the "I will compile" message.