Tuple
s have this nice behavior:
z8 = (Int8(0),Int8(0))
z64 = (0,0)
a8 = Vector{Tuple{Int8, Int8}}()
a64 = Vector{Tuple{Int64, Int64}}()
# these all work
push!(a8, z8)
push!(a64, z64)
push!(a8, z64)
push!(a64, z8)
At first I thought the behavior I wanted was related to Tuple
s being covariant in their type parameters [1] (which doesn’t make sense because there’s no subtype relationship between Int8
and Int64
, and I would also need contravariance at the same time). But instead he behavior I want is due to the convert
methods defined on Tuple
[2].
# previous `push!`s work because these all work
convert(eltype(a8), z8)
convert(eltype(a64), z64)
convert(eltype(a8), z64)
convert(eltype(a64), z8)
I would like to apply this behavior to another type I define:
struct Wrap{T}
x::T
end
w8 = Wrap(z8)
w64 = Wrap(z64)
b8 = Vector{Wrap{Tuple{Int8, Int8}}}()
b64 = Vector{Wrap{Tuple{Int64, Int64}}}()
# I want all of these to work
push!(b8, w8)
push!(b64, w64)
push!(b8, w64)
push!(b64, w8)
# which requires all of these to work.
convert(eltype(b8), w8)
convert(eltype(b64), w64)
convert(eltype(b8), w64)
convert(eltype(b64), w8)
I can get my desired Wrap
behavior by defining
Base.convert(::Type{Wrap{T}}, w::Wrap) where {T} = Wrap(convert(T, w.x))
but I’m hoping there’s an existing idiom for defining a similar method across all fields of a given type.
Related discussion:
[1] Types · The Julia Language
[2] https://github.com/JuliaLang/julia/blob/2d5741174ce3e6a394010d2e470e4269ca54607f/base/essentials.jl#L301-L314