Macro.expand/2 not working as expected

I’m going through this macro tutorial by Sasa Juric: https://www.theerlangelist.com/article/macros_1

One thing that is confusing me however is that Macro.expand/2 doesn’t seem to do the same thing as the tutorial suggests.

This is the part.

iex(3)> quoted = quote do Tracer.trace(1+2) end
{{:., [], [{:__aliases__, [alias: false], [:Tracer]}, :trace]}, [],
 [{:+, [context: Elixir, import: Kernel], [1, 2]}]}
iex(4)> expanded = Macro.expand(quoted, __ENV__)
{:__block__, [],
 [{:=, [],
   [{:result, [counter: 5], Tracer},
    {:+, [context: Elixir, import: Kernel], [1, 2]}]},
  {{:., [], [{:__aliases__, [alias: false, counter: 5], [:Tracer]}, :print]},
   [], ["1 + 2", {:result, [counter: 5], Tracer}]},
  {:result, [counter: 5], Tracer}]}

When I follow along and do Macro.expand(quoted, __ENV__) it simply returns the quoted AST completely unchanged, it doesn’t expand anything and I don’t understand why…

Works for me, did you make sure to require Tracer ? Can you show your Tracer module? If you typed it out yourself, did you accidentally do def tracer instead of defmacro tracer?

iex(3)> require Tracer
Tracer
iex(4)> Tracer.trace(1 + 2)
Result of 1 + 2: 3
3
iex(5)> ast = quote do: Tracer.trace(1 + 2)                 
{{:., [], [{:__aliases__, [alias: false], [:Tracer]}, :trace]}, [],
 [{:+, [context: Elixir, import: Kernel], [1, 2]}]}
iex(6)> Macro.expand(ast, __ENV__)                          
{:__block__, [],
 [
   {:=, [],
    [
      {:result, [counter: -576460752303422655], Tracer},
      {:+, [context: Elixir, import: Kernel], [1, 2]}
    ]},
   {{:., [],
     [
       {:__aliases__, [counter: -576460752303422655, alias: false], [:Tracer]},
       :print
     ]}, [], ["1 + 2", {:result, [counter: -576460752303422655], Tracer}]},
   {:result, [counter: -576460752303422655], Tracer}
 ]}
3 Likes

after doing it again and it working fine, I was even more confused as to why it was working now, but I found the problem…

I had:

quoted = quote do Tracer.trace(1+2) end

instead of

quoted = quote do: Tracer.trace(1+2)

Whoops!

That works fine for me too:

quoted = quote do Tracer.trace(1+2) end
{{:., [], [{:__aliases__, [alias: false], [:Tracer]}, :trace]}, [],
 [{:+, [context: Elixir, import: Kernel], [1, 2]}]}
iex(8)> Macro.expand(quoted, __ENV__)          
{:__block__, [],
 [
   {:=, [],
    [
      {:result, [counter: -576460752303422591], Tracer},
      {:+, [context: Elixir, import: Kernel], [1, 2]}
    ]},
   {{:., [],
     [
       {:__aliases__, [counter: -576460752303422591, alias: false], [:Tracer]},
       :print
     ]}, [], ["1 + 2", {:result, [counter: -576460752303422591], Tracer}]},
   {:result, [counter: -576460752303422591], Tracer}
 ]}

Not sure what your issue was but quote do end is perfectly legal.

1 Like

If I didn’t have the terminal history I’d have sworn I was going senile, i did precisely that and it didn’t work.

I honestly have no idea what happened, it might be some weird stuff to do with recompiling. Maybe you have to require again after a recompile. I used recompile without exiting the shell after I edited the macro so maybe that breaks things some how… no idea… something to keep in mind, but if anyone has any idea what is happening behind the scenes that would cause that, it would be interesting to know!