Let's say I want to define a series of struct
s that will be used as parametric types for some other struct
later on. For instance, I would like to have something like
abstract type Letter end
struct A <: Letter end
struct B <: Letter end
...etc...
The idea I've had is to define a macro which takes a string of the name of the struct
I want to create and defines it as well as some basic methods. I would then execute the macro in a loop for all names and get all my structs defined at compile time. Something like this:
const LETTERS = ["A","B","C","D"]
abstract type Letter end
macro _define_type(ex)
lines = Vector{Expr}()
push!(lines, Meta.parse("export $ex"))
push!(lines, Meta.parse("struct $ex <: Letter end"))
push!(lines, Meta.parse("string(::Type{$ex}) = \"$ex\""))
return Expr(:block,lines...)
end
@_define_type "A"
for ex in LETTERS
@_define_type ex
end
The first way of executing the macro (with a single string) works and does what I want. However, when I execute the macro in a loop it does not. It tells me some variables are declared both as local and global variables.
Can someone explain what is happening? I believe it may be solved by a proper use of esc
, but I can't figure out how.
Thanks!
Edit: Thank you all for the amazing responses! Got my code running!
I think this is what you are trying to do:
module MyModule
abstract type Letter end
const LETTERS = ["A", "B", "C", "D"]
for letter in LETTERS
sym = Symbol(letter)
@eval begin
export $sym
struct $sym <: Letter end
Base.string(::Type{$sym}) = $letter
end
end
end
using .MyModule
string(A) # "A"
See the Code Generation section for more details: https://docs.julialang.org/en/v1/manual/metaprogramming/#Code-Generation