Hi - yet another help request in regards to macros. I’ve been trying multiple approaches to no avail.
Let’s say I have a code like this:
module Z
export z
function z(m = @__MODULE__, a='a'; c...)
"$m :: $a & $(c...)"
end
end
module A
using ..Z
z(@__MODULE__, 'b', x='x')
end
resulting in "Main.A :: b & :x => 'x'"
I don’t like how I have to pass @__MODULE__
when invoking z
and I would like to write a macro Z.@z
which uses its __module__
argument and automatically invokes z
passing in all the other arguments. So it will be invoked as @z('b', x='x')
and will return the same "Main.A :: b & :x => 'x'"
I tried many approaches, but nothing worked (got an error that macros don’t take keyword arguments, I tried sending an expression and manipulating its args, etc). I find it quite tricky.
Thank you
1 Like
No feedback… Wondering if it’s because it’s too simple and I’m missing something… Or too complicated. Curious at least about the best approach, if anybody tried to achieve something similar.
I think this is more or less what you want:
module Z
export @z
function _z(m = @__MODULE__, a='a'; c...)
"$m :: $a & $(c...)"
end
macro z(arglist)
args = []
for arg in arglist.args
if isa(arg, Expr)
argexpr = :($(esc(arg.args[1])) = $(esc(arg.args[2])))
argexpr.head = :kw
push!(args, argexpr)
else
push!(args, :($(esc(arg))))
end
end
:(_z($__module__, $(args...)))
end
end
module A
using ..Z
y = 'x'
w = 'b'
println(@z (w, x=y))
end
Does it work for you?
@mateuszbaran Thank you, it does!
The problem though is that the syntax is very “unjulian” - one has to pass an invalid tuple as an expression - which is very error-prone. The regular ways of invoking macros, which would be either @z('b', x='x')
or @z 'b', x='x'
, both error out. This can be very confusing for a regular user of the API which doesn’t expect that this is, in fact, a special case of an invocation.
I’ve been struggling with this a lot - I’m starting to think that maybe it can’t be done given how the language works.
Do you want something like this?
You can also make @z
accept variable numer of arguments, and @z('b', x='x')
will work. With some effort, most user errors can be checked for in the macro itself.
Thanks for the tip - can’t tell, at first sight, I need to try it out. But it might work, I didn’t realise one can have @macro(ex, args...)
- I tried with both @macro(ex)
and @macro(args...)
but ultimately failed. This might do the trick.
Yes, I think it’s what @pfitzseb pointed to, right? Is that what you have in mind? Thanks
Yes, something like that .