Using eval inside macro?

I have a macro that takes a type as input and enhances it with a keyword constructor.

struct Foo a;z end
@macroexpand @keyword_constructor Foo
:(Foo(; a=nothing, z=nothing) = begin  # In[2], line 9:
            Foo(a, z)
        end)

This relies on using eval inside the macro and I vaguely remember that using eval inside a macro is considered evil.

  • Why is eval inside a macro a bad idea in general?
  • Is it okay in this particular case?
macro keyword_constructor(T)
    M = current_module()
    fields = eval(M, :(fieldnames($T)))
    kws = map(field -> Expr(:kw, field, :nothing), fields)
    esc(:($T(;$(kws...)) = $T($(fields...))))
end
1 Like

eval in macro can easily evaluate in the wrong scope. It is totally OK if the intended sematic is to evaluate the part of the expression only in top-level (global) scope, which includes macros that should only be used in global scope, like @enum. You should also make sure the eval is done in the right module (current_module() pre-0.7 and __module__ post-0.7).

5 Likes

I see thanks!

You might also be interested in the currently non-exported @kwdef macro

2 Likes

Thanks I was not aware of that! There is also QuickTypes.jl, which I find useful. The advantage of the above approach is that the typedef itself does not need to be decorated, making it easier to combine with other typedef tweaks.