I am trying to wrap my skull around metaprogramming. Feels like a stiff skull.
In my little example, I want a function that can take any composite type, and do some manipulation (here printing) of each field. Here we go
using StaticArrays
@generated function insight(f)
print("Generating insight.\n")
e = quote end
for fi in fieldnames(f)
blk = quote
print(string(fi),"::",string(typeof(f.$fi))," → ",show(f.$fi),"\n")
end
append!(e.args, blk.args)
end
return e
end
struct typo{nx}
σ::SMatrix{nx,nx}
b
c
end
nx = 3
i = typo{nx}(randn(nx,nx),π,3.)
insight(i)
I get “undefVarError: fi not defined.”
I know a “generated function” has access to type info, not values, at … generation time. I reckon fieldnames should be fair game. Are the fieldnames known at generation time? Is that the cause of the error anyway?
I also welcome comments on the way I append stuff. Is there simpler?
The first string(fi) is quoted, so it will be evaluated when the (generated) function is called. fi is not a variable in your generated function, so it’s an error. You probably want $(string(fi)) to evaluate it at generation-time.
The second string should work fine. But it will be performing the computation at runtime, since only $fi will be evaluated at generation time. You could use $(string(fieldtype(f, fi))) to do it at compile-time (though note that it’s not quite the same computation — your version shows the type of the value stored, but my version shows the type of the field)
@generate function foo(data)
generation time code
return quote
runtime code $(generation time code)
end
My code now works
using StaticArrays
@generated function insight(f)
print("Generating insight.\n")
e = quote end
for fi in fieldnames(f)
blk = quote
print($(string(fi))," :: ",$(string(fieldtype(f,fi)))," → ",string(f.$fi),"\n")
end
append!(e.args, blk.args)
end
return e
end