Spotted a rookie macro mistake in my code. I only bothered to experiment a little within the Main module
, so it doesn’t cover macro hygiene at all; basically, that’s whether the variables in the expression are considered to belong to the macro definition’s module or the macro call’s module. As it is, all the variables will be considered to belong to the macro definition module, but in this context, you likely want the code you write to belong to whereever you write it, and the only new symbol the macro introduces, convert
, should belong to Base
unconditionally. So, I’m putting the amended macro here, it’s a very small change:
julia> macro convertdo(type::Symbol, doblock::Expr)
if doblock.head != :do throw(ArgumentError("@convertdo's 2nd argument must be do-block.")) end
callexpr, anonfunc = doblock.args[1], doblock.args[2]
arg1 = if (callexpr.args[2] isa Expr && callexpr.args[2].head == :parameters) 3 else 2 end
insert!(callexpr.args, arg1, :(Base.convert($type, $anonfunc)) )
esc(callexpr) # entire expression belongs to macro call module
end
@convertdo (macro with 1 method)
julia> @macroexpand @convertdo MyType dosomething([1 2;3 4], "EE"; hi="hello") do x
x^2
end
:(dosomething(Base.convert(MyType, ((x,)->begin
#= REPL[4]:2 =#
x ^ 2
end)), [1 2; 3 4], "EE"; hi = "hello"))
See how all the Main._
from the first version’s @macroexpand
vanishes, and the do-block’s argument stays as written instead of being changed? Those changes were the variables being resolved in the macro definition scope by default. If you ever need to use the macro outside its definition module, I expect this would fix the immediate bugs.