Custom implicit type conversion

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.

1 Like