Is this generated function for struct2tuple safe to use?

I’m not really sure if this function could be used safely when I have a struct with mutable fields in it:

@generated function struct2tuple(x::T) where T
    n = fieldcount(T)
    exprs = [:(getfield(x, $(i))) for i in 1:n]
    return Expr(:tuple, exprs...)
end

is it forbidden? It seems that the manual says something against this when talking about observing mutable states, but it seems to work fine e.g.

julia> struct A
           x::Vector{Int}
           y::Vector{Float64}
       end

julia> struct2tuple(A([1], [1.]))
([1], [1.0])

But I’m a total beginner in these kind of things so I’m unsure.

Maybe I’m wrong, but if “observing mutable states” means that I base any code generation decision on mutable values, then this should be safe.

Generated functions must not mutate or observe any non-constant global state (including, for example, IO, locks, non-local dictionaries, or using hasmethod).

you’re fine I think, you’re not mutating any non-constant global state, and I don’t think fieldcount(T) is a mutable global state.

1 Like

technically fieldcount is a generic function which could be overloaded for a specific type.
But if that happens a lot of other things will probably break,
so you are already in hell.
This code is fine basically.

1 Like

This doesn’t answer your question, but in your specific case you can replace the generated function by

struct2tuple(x::T) where T = ntuple(i -> getfield(x, i), Val(fieldcount(T)))

(I didn’t check that this remains efficient for structs with very many fields.)

2 Likes

Nice, yes, it seems to work fine in my use case. I had the same function without the Val and it wasn’t working efficiently, but with that it does.

Thanks a lot to all of you!

1 Like

Also check ConstructionBase.jl: it has getfields(your_obj) and getproperties(your_obj).
It’s a very lightweight package, a large fraction of Julia ecosystem depends on it.

1 Like