Implicit cast of a struct into a tuple


Is there a way to define an implicit cast of a struct into a tuple, such that the following syntax becomes valid:

struct T ; x::String ; y::Integer ; end

t = T("x", 1)
a, b = t

Not sure if a, b = t is possible, I’ve never seen customizing assignments, but you can put the fields of a struct instance into a tuple:

function struct2tuple(inst)
  numfields = fieldcount(typeof(inst))
  ntuple(i -> getfield(inst, i), numfields) 

a, b = struct2tuple(t)  # a::String, b::Int64

Note that the method is type-unstable if the struct has any abstract field types. Tuple{String, Integer} is an abstract type because Tuples can’t hold pointers like a struct can. struct2tuple returns the concrete type Tuple{String, Int64}.

For destructuring to work, you “simply” need to define how to iterate over instances of your struct. Note that this has the (potentially unintended) side effect that one can then iterate on fields of your struct in all other contexts as well.

Since you want iteration on your struct to behave like iteration over the tuple of field values, one way to do that is to borrow the implementation of iteration on tuples:

julia> struct T

# calling `iterate` on t is like calling `iterate` on the tuple `(t.x, t.y)`
julia> Base.iterate(t::T, args...) = iterate((t.x, t.y), args...)

julia> a, b = T("a", 1)
T("a", 1)

julia> a, b
("a", 1)

There is UnPack.jl package which allows to do this

@unpack x, y = t

Though, the names in the tuple should match the fields in the struct.

1 Like

This functionality is in base now:

(; x, y) = t