Search code examples
macrosjuliametaprogrammingdefault-constructor

How to pass a macro-argument to an expression within the same macro?


macro myMacro(name,arg)
    :(struct $name
       $(esc(arg.args[1]))
       function $name(;$(esc(arg.args[1]))=arg.args[2].args[2])
         new($(esc(arg.args[1])))
       end
    end)
end

I'm trying to create a struct with a default value that spouses to be the second argument from the macro. I know when I define arg.args[2].args[2] as default argument it will give an error, cause arg.args[2].args[2] is not defined inside the struct but I have no idea how to define it.

The macro should expand to:

macroexpand(Main,:(@myMacro myM ((arg,(default=10)))))


:(struct myM
      arg
      function myM(; arg = 10)
          new(arg)
      end)

Solution

  • You were close, just a couple of issues:

    1. The esc isn't necessary here. Usually, to avoid conflicts with variables in the macro calls' scopes, variables local to the macro's returned expression are renamed by gensym, and global variables are taken from the macro definition's scope. esc undos this for an expression, so variables in that expression could mix with the macro call scope. In your case, the variables you tried to esc are local to a struct and a function, no chance of mixing with the macro call scope anyway.

    2. You forgot to interpolate the arg.args[2].args[2] bit.

    macro myMacro(name,arg)
        :(struct $name
           $(arg.args[1])
           function $name(; $(arg.args[1]) = $(arg.args[2].args[2]) )
             new( $(arg.args[1]) )
           end
        end)
    end