I am wrapping NamedTuple to define some new/different behaviour without committing type piracy and ran into the following problem:
struct Wrapper{SYMS, TT}
x::NamedTuple{SYMS, TT}
end
randnt() = Wrapper((a = randn(), b = rand(), c = rand(1:5), d = randn(SVector{3, Float64})))
X = randnt()
@allocated randnt() # 64
isbits(X) # false
isbits(X.x) # true
This is not good, I really need Wrapper
to be non-allocating. Does this have anything to do with the fact that Symbol
is not isbits
?
Bizarrely, though, (for me anyhow…)
struct Wrapper1{NT}
x::NT
end
randnt1() = Wrapper1((a = randn(), b = rand(), c = rand(1:5), d = randn(SVector{3, Float64})))
X1 = randnt1()
@allocated randnt1() # 0
isbits(X1) # true
isbits(X1.x) # true
I cannot grasp the fundamental different between these two.
To explain why I prefer the first implementation Wrapper
: I use quite a few generated functions which need the SYMS
information. With a tiny bit of extra code this can of course be done for Wrapper1
as well, so not too big a deal. (well-somewhat, I now have to fix a few 100 lines of code and not introduce bugs). But I am very curious and would like to understand what the difference here is?