You were very close! :)
Macros can have type annotations too, they are functions that work at compile time, but their inputs can only be Exprs, Symbols or constant values, ie: Int, macros don't evaluate their inputs before being invoked, like functions do before being called, macros work on syntax.
julia> macro m(a::Symbol, b) # in ths method a should allways be a symbol
# use spaces and parens as needed to delimit and
# group args as needed, not commas in this case
@show a b # or use this: @show(a, b) notice comma here
ex = quote # there is no need to use eval here a macro
$a = $b # will compile and evaluate the returning
end # expression when invoked
@show ex
return esc(ex) # esc will use surrounding scope instead of gensyms
end
@m (macro with 1 method)
Do not use eval inside the body of a macro, in this case it is in the body of the returned expression (there are cases when this could be needed, but this is not one of them).
julia> x = 2
2
Honestly I don't know yet how to make interpolations similar to macros like @eval or BenchmarkTools.@btime work (should be explained in the manual, I will have to study the code of those macros), but you don't need $ when invoking the macro here for your simple example.
julia> @m y (x + 1) # parens for grouping, or @m(y, x + 1)
a = :y # :y is a symbol
b = :(x + 1)
ex = quote
#= REPL[17]:4 =#
y = x + 1
end
3
If you don't use esc it will hygienically create gensyms, in this case it uses the surrounding scope variables instead.
julia> @m z rand(x, y)
a = :z
b = :(rand(x, y))
ex = quote
#= REPL[17]:4 =#
z = rand(x, y)
end
2×3 Array{Float64,2}:
0.817233 0.623775 0.277464
0.421573 0.443654 0.296359
gensyms look like this:
julia> gensym(:foo)
Symbol("##foo#924")