# How to convert element type of a container?

**URL:** <https://discourse.julialang.org/t/how-to-convert-element-type-of-a-container/20293>\
**Category:** General Usage\
**Tags:** question, array, type, convert\
**Created:** [January 30, 2019, 9:35pm UTC](https://discourse.julialang.org/t/how-to-convert-element-type-of-a-container/20293 "2019-01-30T21:35:15Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)\
**Post date:** [January 30, 2019, 9:35pm UTC](https://discourse.julialang.org/t/how-to-convert-element-type-of-a-container/20293/1 "2019-01-30T21:35:15Z")

</div>

Suppose I have a container, `a`, could be a `Tuple`, a `Vector`, or a user-defined subtype of `AbstractArray`. Now I want to convert every element of `a` to another type, e.g., from `Int`s to `Float64`. For example, I write a rough function:

```julia
convert_eltype(T::Type, a) = map(x -> convert(T, x), a)

```

This function works fine with `Tuple` and `Vector`, but not the last one.

```julia
julia> using StaticArrays

julia> struct A{T} <: FieldVector{2, T}
             x::T
             y::T
         end

julia> convert_eltype(Float64, A(1, 2))
2-element SArray{Tuple{2},Float64,1,2}:
 1.0
 2.0

```

This breaks the container type `A`:

```julia
julia> f(::A) = 1
f (generic function with 1 method)

julia> f(convert_eltype(Float64, A(1, 2)))
ERROR: MethodError: no method matching f(::SArray{Tuple{2},Float64,1,2})
Closest candidates are:
  f(::A) at REPL[7]:1
Stacktrace:
 [1] top-level scope at none:0

```

I also tried other ways:

```julia
convert_eltype(T::Type, a) = typeof(a)(map(x -> convert(T, x), a))

```

But it does not work. `typeof(a)` contains the `Int` information which makes `map(x -> convert(T, x), a)` work in vain.  
I try to strip the container type but am told it seems [not possible](https://discourse.julialang.org/t/how-to-get-the-container-type-of-a-container/20253/6). I do not find `similar` useful because it just constructs a new uninitialized container, not converting one type to another.

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [January 30, 2019, 9:53pm UTC](https://discourse.julialang.org/t/how-to-convert-element-type-of-a-container/20293/2 "2019-01-30T21:53:08Z")

</div>

Define a `StaticArrays.similar_type` method for your `FieldVector`. See [Is there a way to seamlessly inherit vector arithmetic on new types? - #9 by tkoolen](https://discourse.julialang.org/t/is-there-a-way-to-seamlessly-inherit-vector-arithmetic-on-new-types/19713/9).

---

<div class="post-metadata">

**Author:** ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)\
**Post date:** [January 30, 2019, 11:11pm UTC](https://discourse.julialang.org/t/how-to-convert-element-type-of-a-container/20293/3 "2019-01-30T23:11:35Z")

</div>

That’s a good way of doing this. I have read the [doc of `similar_type`](http://juliaarrays.github.io/StaticArrays.jl/latest/pages/api.html#similar_type()-1), and I found that this only works with concrete type `AA`:

```julia
julia> using StaticArrays

julia> import StaticArrays: similar_type

julia> export similar_type

julia> struct AA{T} <: FieldVector{2, T}
           x::T
           y::T
       end

julia> convert_eltype(T::Type, a) = map(x -> convert(T, x), a)
convert_eltype (generic function with 1 method)

julia> similar_type(::Type{A}, ::Type{T}, size::Size) where {A <: AA, T} = AA{T}
similar_type (generic function with 18 methods)

julia> similar_type(AA, Float64, Size(2))
AA{Float64}

julia> convert_eltype(Float64, AA(1, 2))
2-element AA{Float64}:
 1.0
 2.0

```

But if `AA` is an abstract type and it has several subtypes, this will break:

```julia
julia> abstract type M{N, T} <: FieldVector{N, T} end

julia> struct AA{T} <: M{2, T}
           x::T
           y::T
       end

julia> convert_eltype(T::Type, a) = map(x -> convert(T, x), a)
convert_eltype (generic function with 1 method)

julia> similar_type(::Type{A}, ::Type{T}, size::Size) where {A <: M, T} = A{T}
similar_type (generic function with 18 methods)

julia> similar_type(AA, Float64, Size(2))
AA{Float64}

julia> convert_eltype(Float64, AA(1, 2))
ERROR: TypeError: in Type{...} expression, expected UnionAll, got Type{AA{Int64}}
Stacktrace:
 [1] similar_type(::Type{AA{Int64}}, ::Type{Float64}, ::Size{(2,)}) at ./REPL[7]:1
 [2] macro expansion at /Users/qz/.julia/packages/StaticArrays/mcf7t/src/mapreduce.jl:30 [inlined]
 [3] _map(::getfield(Main, Symbol("##3#4")){DataType}, ::Size{(2,)}, ::AA{Int64}) at /Users/qz/.julia/packages/StaticArrays/mcf7t/src/mapreduce.jl:21
 [4] map at /Users/qz/.julia/packages/StaticArrays/mcf7t/src/mapreduce.jl:11 [inlined]
 [5] convert_eltype(::Type, ::AA{Int64}) at ./REPL[6]:1
 [6] top-level scope at none:0

```

It does not seem to be my problem: The error happens in [StaticArrays.jl](http://juliaarrays.github.io/StaticArrays.jl/latest/). So the only way is that I add a method for each subtype of `M`?

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [January 30, 2019, 11:44pm UTC](https://discourse.julialang.org/t/how-to-convert-element-type-of-a-container/20293/4 "2019-01-30T23:44:09Z")

</div>

This is basically the same question you asked in [How to get the container type of a container?](https://discourse.julialang.org/t/how-to-get-the-container-type-of-a-container/20253). You’ll have to define a `similar_type` overload for each _concrete_ `FieldVector` subtype you define. If that’s too much of a hassle, you could write a macro to generate the `similar_type` method along with the `FieldVector` subtype definition.

Note by the way that you’ll want to be more specific with the `Size` argument:

```julia
StaticArrays.similar_type(::Type{<:AA}, ::Type{T}, ::Size{(2,)}) where {T} = AA{T}

```

otherwise,

```julia
julia> aa = AA(1, 2)
2-element AA{Int64}:
 1
 2

julia> [aa; aa]
ERROR: DimensionMismatch("No precise constructor for AA{Int64} found. Length of input was 4.")
Stacktrace:
 [1] AA{Int64}(::Tuple{Tuple{Tuple{NTuple{4,Int64}}}}) at /Users/tkoolen/.julia/packages/StaticArrays/mcf7t/src/convert.jl:1
 [2] Type at /Users/tkoolen/.julia/packages/StaticArrays/mcf7t/src/convert.jl:4 [inlined] (repeats 3 times)
 [3] macro expansion at /Users/tkoolen/.julia/packages/StaticArrays/mcf7t/src/linalg.jl:114 [inlined]
 [4] _vcat at /Users/tkoolen/.julia/packages/StaticArrays/mcf7t/src/linalg.jl:96 [inlined]
 [5] vcat(::AA{Int64}, ::AA{Int64}) at /Users/tkoolen/.julia/packages/StaticArrays/mcf7t/src/linalg.jl:92
 [6] top-level scope at none:0

```

---

<div class="post-metadata">

**Author:** ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)\
**Post date:** [January 30, 2019, 11:47pm UTC](https://discourse.julialang.org/t/how-to-convert-element-type-of-a-container/20293/5 "2019-01-30T23:47:28Z")

</div>

That’s indeed why I asked [this question](https://discourse.julialang.org/t/how-to-get-the-container-type-of-a-container/20253). I am surprised that Julia does not provide a simple way of doing this.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [January 30, 2019, 11:56pm UTC](https://discourse.julialang.org/t/how-to-convert-element-type-of-a-container/20293/6 "2019-01-30T23:56:43Z")

</div>

> [@singularitti](#):
>
> ```julia
> (::Type{A}, ::Type{T}, size::Size) where {A <: M, T} = A{T}
> 
> ```

The key thing is that Julia doesn’t enforce that the first type parameter of `A` here is the same type parameter that appears in `M{_, T}`. In fact, another person could come along and define a

```julia
      struct BB{T, S, R} <: M{2, R}
           x::R
           y::R
           bonus::T
           more::S 
       end

```

Now your generic `similar_type` method is no longer correct.
