I know this is an old thread, but I think the question not out-dated. I just stumbled across a blog with the following proposal
EDIT: I adapted the macro @kwredef
to also include cases with typed structs.
macro redefinable(struct_def)
struct_def isa Expr && struct_def.head == :struct || error("struct definition expected")
if struct_def.args[2] isa Symbol
name = struct_def.args[2]
real_name = struct_def.args[2] = gensym(name)
elseif struct_def.args[2].head == :<:
name = struct_def.args[2].args[1]
real_name = struct_def.args[2].args[1] = gensym(name)
end
esc(quote
$struct_def
$real_name.name.name = $(QuoteNode(name)) # fix the name
$name = $real_name # this should be `const $name = $real_name`
end)
end
This approach is somewhat similar to one of the approaches above in that it creates a true struct
. The advantage is that the name is identical to the struct that you would normally define.
The only disadvantage could be that it creates a lot of structs and doesn’t check whether the new structure is identical to the old one. But for development purposes this shouldn’t be a problem. Also, the variable which holds the struct type could be overwritten.
I was about doing a similar thing for Base.@kwdef
and borrowed some of this ideas:
macro kwredef(expr)
expr = macroexpand(__module__, expr) # to expand @static
expr isa Expr && expr.head === :struct || error("Invalid usage of @kwredef")
expr = expr::Expr
t = expr.args; n = 2
if t[n] isa Expr && t[n].head === :<:
t = t[n].args
n = 1
end
curly = t[n] isa Expr && t[n].head === :curly
if curly
t = t[n].args
n=1
end
T_old = t[n]
t[n] = T_new = gensym(T_old)
esc(quote
Base.@kwdef $expr
$T_old = $T_new
$curly ? $T_new.body.name.name = $(QuoteNode(T_old)) : $T_new.name.name = $(QuoteNode(T_old)) # fix the name
end)
end