I expect this macro to define variables with same characters, but it doesn’t work.
How should I write this?
macro chars(cs...)
return :( $(esc(cs)) = $(map(c->string(c)[1], cs)) )
end
@chars a b c # is '(a,b,c) = ('a','b','c')
I expect this macro to define variables with same characters, but it doesn’t work.
How should I write this?
macro chars(cs...)
return :( $(esc(cs)) = $(map(c->string(c)[1], cs)) )
end
@chars a b c # is '(a,b,c) = ('a','b','c')
macro chars(cs...)
return :( $(esc(Expr(:tuple, cs...))) = $(map(c->string(c)[1], cs)) )
end
@chars a b c
I did
dump(quote
a,b,c = 1,2,3
end)
to figure it out.
Thank you. I have a question. What difference is it between cs
and Expr(:tuple, cs...)
? cs
returns (:a :b :c)
. This is a tuple of symbols, isn’t it? I guess that Expr(:tuple, cs...)
is a tuple of symbols too. Why did cs
fail?
julia> dump(:((:a,:b,:c)))
Expr
head: Symbol tuple
args: Array{Any}((3,))
1: QuoteNode
value: Symbol a
2: QuoteNode
value: Symbol b
3: QuoteNode
value: Symbol c
typ: Any
vs
julia> dump(Expr(:tuple, :a, :b, :c))
Expr
head: Symbol tuple
args: Array{Any}((3,))
1: Symbol a
2: Symbol b
3: Symbol c
typ: Any
If you find Julia ASTs confusing, you are not alone
This one had me scratching my head:
julia> dump(:(a,b,c = 1,2,3))
Expr
head: Symbol tuple
args: Array{Any}((5,))
1: Symbol a
2: Symbol b
3: Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol c
2: Int64 1
typ: Any
4: Int64 2
5: Int64 3
typ: Any
Julia does not do left-hand-side destructuring on tuples (which cs
is); it does destructuring on Expr
objects. It is confusing, but not much can be done about it. As Stefan said, Julia suffers from “the curse of syntax”.
I got it. Macros works on Expr which is not Tuple, of cause, and is not Array too. To write macro in Julia, I have to takes care of Expr only,
I saw that. My saying was wrong, the first is a tuple of quoted symbol, isn’t it? Expr doesn’t quote its arguments like (:a :b :c)
, while :
quotes its arguments like (:(:a), :(:b), :(:c))
. Julia’s expanding rules confuse me, but your link is so helpful for me. Thank you!
In general it is always much more robust, precise, and reliable to use the Expr
constructor, so I recommend always trying out dump
and then using the constructor if you want to do reliable metaprogramming.
I generally think the opposite; since I am not sure how stable the internal representation of the AST is going to be, I am always reluctant to use Expr
, and prefer when something else is available (eg Meta.quot
, splicing into expressions, etc).
My experience is different. Expr
seems to be more reliable. For example, when abstract Name
was changed to abstract type Name end
, the Expr(:abstract,:Name)
would still work in both the old and new versions of Julia, so therefore the Expr
way of doing it is more reliable and robust in the long run.