An easy question. I have asked it some time back and got a good answer, but cannot find back to it, not on Discourse, not in the manual, and not in my code…
I want to write a macro to generate code like
getfield(vari,:something) = something
so I code
macro mack(out,name)
return esc(quote
getfield($out,$name) = $name
end)
end
@mack(vari,:something)
and the rub is, on the right hand side of the assignment I want $name to be interpolated as something
, not :something
.
And yes, I reckon you can workaround this example with
macro mack(out,name)
return esc(quote
$out.$name = $name
end)
end
@mack(vari,something)
but that won’t help me for my real problem.
This code doesn’t make sense so it is hard to know what you are trying to do. Maybe this is useful though (note the usage of QuoteNode
):
julia> macro mack(name)
return :($(QuoteNode(name)), $(esc(name)))
end;
julia> @macroexpand @mack foo
:((:foo, foo))
julia> foo = 3; @mack foo
(:foo, 3)
3 Likes
Hi Kristoffer,
Guilty as charged. I did not test my simplification, and made it a nonsense. I wish I had written
macro mack(out,name)
return esc(quote
setfield!($out,$name,$name)
end)
end
@mack(vari,:something)
which (modified with help), would return
setfield!(vari,:something,something) # vari.something = something
I take note of the QuoteNode, which does the trick if the macro call is
@mack vari something
however, I want to write a macro called like this
@mack vari :something
(Well, of course, the conclusion may be that giving a Symbol as macro argument is just a way to make life difficult…) But assuming I stick to the later call syntax, any way to interpolate something
(not :something
) in the code?
Whenever you write macros, you should invest time into running dump
on any syntax you plan to process:
julia> dump(:(x))
Symbol x
julia> dump(:(:x))
QuoteNode
value: Symbol x
If it’s important that users pass in something that syntactically looks like a symbol, you need to do the relevant unwrapping or wrapping inside your macro to handle that case.
1 Like
First: dump is a very nice function I didn’t know about! Good tip.
Second: what you say is, if the user call the macro with :something
, having examined (with dump) the Expression that the macro receives, I can go grab subexpression directly: the function I was looking for, I can write myself.
Are you sure you want to solve this by macros? If you provide some context, perhaps you will get a solution that does not need metaprogramming at all.
2 Likes
He he!!!
I will not go into that debate for now (I’ll try on my own first), but I’ll keep your question in mind:
You and others helped me a lot in the past weeks when I was working on a macro returning @generated functions. Once all the technicalities of doing that were painstakingly sorted out, someone (and quite possibly you) noted “you don’t need a generated function for that”, which gave me a classic case of Zen-like enlightenment, seeing the power of the combination of method instantiation, data described in the Type and greedy compilation, allowing apparently naive code (a function containing tests on the type of the input) resulting in very efficient compiled code.
Julia rocks.