I would like to contruct a type using meta programming. More specific,I need a tuple type like
Tuple{Vector{String}, Vector{String}}
.
Constructing a value is quite easily possible,
e.g.
ex = Expr(:tuple)
push!(ex.args, 1)
push!(ex.args, 2)
with
eval(ex)
resulting in the tuple value
(1,2)
But how to construct a tuple type?
I used dump to get a syntax tree of the tuple type mentioned above.
dump(:(Tuple{Vector{String}, Vector{String}}))
It results in the following syntax tree:
Expr
head: Symbol curly
args: Array{Any}((4,))
1: Symbol Tuple
2: Expr
head: Symbol curly
args: Array{Any}((2,))
1: Symbol Vector
2: Symbol String
3: Expr
head: Symbol curly
args: Array{Any}((2,))
1: Symbol Vector
2: Symbol String
4: Expr
head: Symbol curly
args: Array{Any}((2,))
1: Symbol Vector
2: Symbol String
However, using the symbol curly, using
ex = Expr(:curly)
did not work to get a well-formed expression so far.
I would be very happy if you had a suggesion.
First, I’ll echo the above that there might be a better way to do this without metaprogramming. Metaprogramming is difficult to write and read and it can be brittle.
To answer your specific query based on the dump you gave (less args[4], which should not actually be present):
julia> ex = Expr(:curly, :Tuple); for _ in 1:2; push!(ex.args, Expr(:curly, :Vector, :String)); end; ex
:(Tuple{Vector{String}, Vector{String}})
julia> ex = :(Tuple{}); for _ in 1:2; push!(ex.args, :(Vector{String})); end; ex # quotes are usually nicer
:(Tuple{Vector{String}, Vector{String}})
Deconstructing the above a bit, notice that :curly needs an args[1] to tell it what is curly to make a “well-formed expression”:
julia> ex = Expr(:curly); push!(ex.args, :Tuple); ex
:(Tuple{})
It’s good to know the Expr structure and how to mutate it regardless; beyond a point, it gets simpler and more efficient than only writing quoted expressions.
I never liked how this is worded. IIRC the basis is that macros and generated functions made up <1% of method definitions in base Julia at some point, but that has some caveats:
eval loops are also metaprogramming.
A lot of Expr and raw string processing is done in plain functions called by macros.
Macro or generated function calls do transform or generate code, so it’s comes across as a bit strange to say metaprogramming is a rare tool then suggest macro calls for routine timing and reflection. Maybe “implementing metaprogramming” would be closer, but that still sounds odd to me.
Some languages don’t specify expression objects like Julia does (though they may expose internals in implementation-specific libraries), changing the concept of metaprogramming. This advice for beginners may backfire, say make a Python user avoid higher-order functions because that’s what most decorators do. I think most people would study enough to avoid that pitfall, but some won’t, might even throw off an AI prompt.