# Reuse \`Tuple\` \`convert\` mechanism in another parametric type

**URL:** https://discourse.julialang.org/t/reuse-tuple-convert-mechanism-in-another-parametric-type/34353
**Category:** General Usage
**Created:** [February 8, 2020, 6:32pm UTC](https://discourse.julialang.org/t/reuse-tuple-convert-mechanism-in-another-parametric-type/34353 "2020-02-08T18:32:06Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![goretkin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goretkin/32/167_2.png) [@goretkin](https://discourse.julialang.org/u/goretkin)
#### Post date: [February 8, 2020, 6:32pm UTC](https://discourse.julialang.org/t/reuse-tuple-convert-mechanism-in-another-parametric-type/34353/1 "2020-02-08T18:32:06Z")

</div>

`Tuple`s have this nice behavior:

```julia
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].

```julia
# 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:

```julia
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

```julia
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:

> [@automatic conversion for fields of a parametric struct](https://discourse.julialang.org/t/automatic-conversion-for-fields-of-a-parametric-struct/10736/2):
>
> Ignore the last part of the error as this is not from a call to a constructor, you are calling convert() directly. As you have just defined this custom type yourself there is no existing method for convert(Type{AwesomeStruct{Union{Void,Int64}}, AwesomeStruct{Void}) But you can easily write a general method for any AwesomeStruct T: julia\> import Base: convert julia\> convert(t::Type{AwesomeStruct{T}}, x::AwesomeStruct) where T = t(x.awesome\_field) convert (generic function with 1 method) jul…

[1] [Types · The Julia Language](https://docs.julialang.org/en/v1/manual/types/#Tuple-Types-1)  
[2] [https://github.com/JuliaLang/julia/blob/2d5741174ce3e6a394010d2e470e4269ca54607f/base/essentials.jl#L301-L314](https://github.com/JuliaLang/julia/blob/2d5741174ce3e6a394010d2e470e4269ca54607f/base/essentials.jl#L301-L314)

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [February 9, 2020, 9:38am UTC](https://discourse.julialang.org/t/reuse-tuple-convert-mechanism-in-another-parametric-type/34353/2 "2020-02-09T09:38:15Z")

</div>

Generally you would need a `convert` method.

Are you looking for an easier way to implement that? Is there a more complex example you need help with? I am asking because for the above, what you are doing may be the simplest solution.

---

<div class="post-metadata">

### Author: ![goretkin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goretkin/32/167_2.png) [@goretkin](https://discourse.julialang.org/u/goretkin)
#### Post date: [February 9, 2020, 7:17pm UTC](https://discourse.julialang.org/t/reuse-tuple-convert-mechanism-in-another-parametric-type/34353/3 "2020-02-09T19:17:32Z")

</div>

I think you understand already, and I’m just looking for a package or some other abbreviated way to do the following:

```julia
function Base.convert(::Type{Wrap3{A, B, C}}, w::Wrap3) where {A, B, C}
  return Wrap3(
    convert(A, w.a),
    convert(B, w.b),
    convert(C, w.c)
  )
end

```

given

```julia
struct Wrap3{A, B, C}
  a::A
  b::B
  c::C
end

```

Seems like it might exist in a package as a macro definition.

---

<div class="post-metadata">

### Author: ![goretkin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goretkin/32/167_2.png) [@goretkin](https://discourse.julialang.org/u/goretkin)
#### Post date: [February 9, 2020, 9:13pm UTC](https://discourse.julialang.org/t/reuse-tuple-convert-mechanism-in-another-parametric-type/34353/4 "2020-02-09T21:13:40Z")

</div>

Another two “features” I’d like:

1. free type parameters

```julia
convert(Tuple{Int64, A} where A, (1.0, 2.0))

```

makes a `(1, 2.0)`

Analogously, I’d like to have this work:

```julia
convert(Wrap3{Int64, Float32, C} where C, Wrap3(1.0, 2, "hey"))

```

1. type parameters that cannot be inferred from constructor arguments:  
I can’t demonstrate this with `Tuple`, but I would hope that whatever mechanism gets me the previously mentioned features would also work as follows

```julia
struct TaggedWrap3{TAG, A, B, C}
  a::A
  b::B
  c::C
end

# allow construction like: TaggedWrap3{:tag}(1,2,3)
function (::Type{TaggedWrap3{TAG,A,B,C} where {A,B,C}})(a,b,c) where {TAG}
  return TaggedWrap3{TAG, typeof(a), typeof(b), typeof(c)}(a,b,c)
end

function Base.convert(::Type{TaggedWrap3{TAG,A,B,C} where {A, B, C}}, w::Wrap3) where {TAG}
  return TaggedWrap3{TAG}(w.a, w.b, w.c)
end

function Base.convert(::Type{TaggedWrap3{TAG,A,B,C}}, w::Wrap3) where {TAG, A, B, C}
  return TaggedWrap3{TAG}(
    convert(A, w.a),
    convert(B, w.b),
    convert(C, w.c)
  )
end

function Base.convert(::Type{TaggedWrap3{Any, A, B, C}}, w::TaggedWrap3{TAG}) where {TAG, A, B, C}
  return TaggedWrap3{TAG}(
    convert(A, w.a),
    convert(B, w.b),
    convert(C, w.c)
  )
end

@show convert(TaggedWrap3{:tag}, Wrap3(1,2,3))
@show convert(TaggedWrap3{:tag, Float64, Float64, Float64}, Wrap3(1,2,3))
@show convert(TaggedWrap3{Any, Float64, Float64, Float64}, TaggedWrap3{:tag}(1,2,3))
# doesn't work, but should
@show convert(TaggedWrap3{:tag, Float64, Float64, C} where C, Wrap3(1,2,3))

```

producing

```julia
convert(TaggedWrap3{:tag}, Wrap3(1, 2, 3)) = TaggedWrap3{:tag,Int64,Int64,Int64}(1, 2, 3)
convert(TaggedWrap3{:tag, Float64, Float64, Float64}, Wrap3(1, 2, 3)) = TaggedWrap3{:tag,Float64,Float64,Float64}(1.0, 2.0, 3.0)
convert(TaggedWrap3{Any, Float64, Float64, Float64}, TaggedWrap3{:tag}(1, 2, 3)) = TaggedWrap3{:tag,Float64,Float64,Float64}(1.0, 2.0, 3.0)

```

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [February 10, 2020, 7:38am UTC](https://discourse.julialang.org/t/reuse-tuple-convert-mechanism-in-another-parametric-type/34353/5 "2020-02-10T07:38:31Z")

</div>

I am not aware of a package like this, but note that the default constructor goes a long way:

```julia
struct Wrap3{A,B,C}
    a::A
    b::B
    c::C
end

Base.convert(::Type{W}, w::Wrap3) where {W <: Wrap3} = W(w.a, w.b, w.c)

convert(Wrap3{Int,Float64,Int8}, Wrap3(1, 2, 3)) # example

```

You can do the same for `TaggedWrap`, just use the `W{TAG}` constructor.
