EDIT: This doesn’t work if I define the below macro in a module and call it outside its module. It defines the new type in the module the macro is defined, not the module the macro is called at.
EDIT2: Solved that by using Core.eval($(__module__), expr) instead of eval(expr)
Thank you very much @rdeits . With your guidance I was able to succeed in what I wanted to do. I post below the full solution for reference. I realized yesterday night that QuoteNode was what I needed, because the docs said that that its useful in nested quotes. But I admit, I couldn’t in the end understand exactly how to use it. Maybe I the metaprogramming docs could use more examples. Oh well, in any case, here’s the final product:
macro copy_type(base_type, newname, extra_fields)
# This macro was generated with the guidance of @rdeits on Discourse:
# https://discourse.julialang.org/t/
# metaprogramming-obtain-actual-type-from-symbol-for-field-inheritance/84912
# We start with a quote. All macros return a quote to be evaluated
quote
let
# Here we collect the field names and types from the base type
# Because the base type already exists, we escape the symbols to obtain it
base_fieldnames = fieldnames($(esc(base_type)))
base_fieldtypes = [t for t in getproperty($(esc(base_type)), :types)]
base_fields = [:($f::$T) for (f, T) in zip(base_fieldnames, base_fieldtypes)]
# Then, we prime the additional name and fields into QuoteNodes
# We have to do this to be able to interpolate them into an inner quote.
name = $(QuoteNode(newname))
additional_fields = $(QuoteNode(extra_fields.args))
# Now we start an inner quote. This is because our macro needs to call `eval`
# However, this should never happen inside the main body of a macro
# There are several reasons for that, see the cited discussion at the top for more
expr = quote
struct $name
$(base_fields...)
$(additional_fields...)
end
end
# @show expr # uncomment this to see that the final expression looks as desired
eval(expr)
end
end
end
mutable struct Example
id::Int
end
@copy_type Example Example5 begin
x::Float64
y::Float64
end