# Most compact way to create an array of a known container type with a different eltype?

**URL:** <https://discourse.julialang.org/t/most-compact-way-to-create-an-array-of-a-known-container-type-with-a-different-eltype/114215>\
**Category:** General Usage\
**Created:** [May 14, 2024, 3:53am UTC](https://discourse.julialang.org/t/most-compact-way-to-create-an-array-of-a-known-container-type-with-a-different-eltype/114215 "2024-05-14T03:53:18Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)\
**Post date:** [May 14, 2024, 3:53am UTC](https://discourse.julialang.org/t/most-compact-way-to-create-an-array-of-a-known-container-type-with-a-different-eltype/114215/1 "2024-05-14T03:53:18Z")

</div>

For example, suppose that we have an array type such as `Atype = Array{ComplexF64,3}` and would like to create an array of the same container type (in this case `Array`) but with a different element type, say `Int` (so the target array type is `Array{Int,K}` for some dimension `K`). The size of the array to create is known. What is the most compact (and least allocating) way to achieve this?

If an instance of `Atype` already exists, we can use `similar`:

```julia
Atype = Array{ComplexF64,3}
a = Atype(undef, (10,10,10)) # size of existing array is (10,10,10)

sz = (3,4) # size of target array is (3,4)
b = similar(a, Int, sz)

```

However, I don’t have an existing `a::Atype` and do not want to create such `a`. The best I have so far is something like

```julia
Atype = Array{ComplexF64,3}
sz = (3,4)
b = similar(Atype(undef, (0,0,0)), Int, sz)

```

but `Atype(undef, (0,0,0))` is still allocating (though very small), and when the dimension of the array is parametrized, the method becomes a bit convoluted:

```julia
K = 3 # parametrized dimension
Atype = Array{ComplexF64,K}
sz = (3,4)
b = similar(Atype(undef, ntuple(k->0,Val(K))), Int, sz)

```

I wished I had something like

```julia
K = 3
Atype = Array{ComplexF64,K}
sz = (3,4)
b = similar(Atype, Int, sz)

```

but this does not work.

Is there a better way than shown above?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [May 14, 2024, 4:15am UTC](https://discourse.julialang.org/t/most-compact-way-to-create-an-array-of-a-known-container-type-with-a-different-eltype/114215/2 "2024-05-14T04:15:11Z")

</div>

I’m sure it’s implied somewhere but why can’t you just do `Array{Int}(undef, sz)`? The only thing preserved from `Atype` is `Array`, so you can just use the constructor directly with the given inputs `Int` and `sz`.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [May 14, 2024, 4:17am UTC](https://discourse.julialang.org/t/most-compact-way-to-create-an-array-of-a-known-container-type-with-a-different-eltype/114215/3 "2024-05-14T04:17:48Z")

</div>

If you know the container, you can curry the parameters in later.

```julia
julia> const container = Array{<: Any,3}
Array{<:Any, 3}

julia> container{ComplexF64}
Array{ComplexF64, 3}

julia> container{Int}
Array{Int64, 3}

```

I suppose what you really want is as follows.

```julia
julia> function replace_eltype(
           A::Type{ <: AbstractArray{T,N}},
           E::Type
       ) where {T, N}
           Base.typename(A).wrapper{E, N}
       end
replace_eltype (generic function with 1 method)

julia> Atype = Array{ComplexF64,3}
Array{ComplexF64, 3}

julia> replace_eltype(Atype, Int)
Array{Int64, 3}

```

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [May 14, 2024, 5:50am UTC](https://discourse.julialang.org/t/most-compact-way-to-create-an-array-of-a-known-container-type-with-a-different-eltype/114215/4 "2024-05-14T05:50:53Z")

</div>

The issue with `replace_eltype` or anything generically manipulating type parameters (with what I’m pretty sure are internals, not API) is that there’s no guaranteed link between parameter order and meaning within a parametric abstract type. For example, this doesn’t go as planned:

```julia
julia> struct DumbArray{Size,T,N} <: AbstractArray{T,N} end

julia> replace_eltype(DumbArray{9, Int, 3}, Bool)
DumbArray{Bool, 3}

```

For a real-world example, StaticArrays.jl. Functions that manipulate the eltype must dispatch on a parametric composite type to preserve it and specifically handle its parameters e.g. `replace_eltype(::Type{DumbArray{Size,T,N}}, E::Type) where {Size,T,N} = DumbArray{Size,E,N}`. Earlier I figured that if there was only 1 parametric composite type in mind, might as well cut to chase for `Array` instantiation; it’s not even feasible to involve `replace_eltype` because all the type parameters were actually replaced.

The iterated union fixing some parameters for a parametric composite type is solid though. Worth mentioning that `const` isn’t necessary for it to work, it’s just separately a good idea for global variables.

---

<div class="post-metadata">

**Author:** ![nalimilan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nalimilan/32/147_2.png) [@nalimilan](https://discourse.julialang.org/u/nalimilan)\
**Post date:** [May 17, 2024, 9:20pm UTC](https://discourse.julialang.org/t/most-compact-way-to-create-an-array-of-a-known-container-type-with-a-different-eltype/114215/6 "2024-05-17T21:20:31Z")

</div>

I’ve wanted this in the past and I thought there was an issue about it, but I can’t find it now. The solution I imagine is that there would be a `similar` method taking a type instead of an instance (and the method taking an instance could call the one defined on a type, just like we already do e.g. for `eltype`).

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [May 17, 2024, 9:23pm UTC](https://discourse.julialang.org/t/most-compact-way-to-create-an-array-of-a-known-container-type-with-a-different-eltype/114215/7 "2024-05-17T21:23:40Z")

</div>

Similar issue: `fmap(float, xs::MyArray{Int64}) :: MyArray{Float64}`

> <https://github.com/JuliaLang/julia/issues/32081>
>
> Currently, broadcasting is heavily specialized to work with array-like (i.e. lin…ear, indexable, and finite) data structures. However, the notion of mapping a function over a parameterized datatype \`F{T}\` applies to many data structures, such as options (\`Some(3)\` vs \`nothing\`) and trees. In fact, this operation is exactly "functor map", which applies over all functor datatypes.
> 
> \[Functors\](https://en.wikipedia.org/wiki/Functor) require that for a given type and its associated "mapping" function (often referred to as \`fmap\` or \`\<$\>\`), the following laws hold (using \[Haskell notation\](https://wiki.haskell.org/Functor)):
> \`\`\`haskell
> fmap id = id
> fmap (f . g) == fmap f . fmap g
> \`\`\`
> In other words, a functor must (a) ensure that mapping the identity function has no effect, and (b) ensure that mapping the function composition \`f ∘ g\` is the same as first mapping \`g\` and then mapping \`f\`.
> 
> From this mathematical definition, we have derived the "broadcasting" functor map operation \`f.(x)\` with \`x::F{T}\` for some type \`F\` which forms a functor. (Note that the second functor law guarantees that "fusion" is valid!)
> 
> This issue proposes that broadcasting be extended to work more seamlessly with other (i.e. non-linear and non-indexable) datatypes, including the fusion feature.
> 
> \`\`\`julia
> julia\> string.(float.(Some(3)))
> Some("3.0")
> 
> julia\> string.(float.(nothing))
> nothing
> \`\`\`
> \`\`\`julia
> julia\> struct Node{T}
> l::Union{Nothing,Node{T}}
> x::T
> r::Union{Nothing,Node{T}}
> end
> const Tree{T} = Union{Nothing,Node{T}}
> Union{Nothing, Node{T}} where T
> 
> julia\> string.(float.(Tree(nothing, 3, Tree(nothing, 4, nothing)))
> Tree{String}(nothing, "3.0", Tree{String}(nothing, "4.0", nothing))
> \`\`\`
> 
> There are a few edge cases to consider, such as combining multiple different functor type in a single broadcast call (e.g. \`f.(\[1,2,3\], Tree(...))\`). Additionally, a slight redesign of broadcasting may be necessary, due to its design focus on axes.

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [May 17, 2024, 10:49pm UTC](https://discourse.julialang.org/t/most-compact-way-to-create-an-array-of-a-known-container-type-with-a-different-eltype/114215/8 "2024-05-17T22:49:36Z")

</div>

> [@wsshin](#):
>
> I wished I had something like
> 
> ```julia
> b = similar(Atype, Int, sz)
> 
> ```

This may be somewhat off-topic: I often wish that also other array-related functions accepted a container type, specifically `zeros` and `ones`. Currently there are also `falses` and `trues` for `BitArray` and `spzeros` for `SparseArray`. If you create your own container type, you have to define yet other functions. This gives a whole zoo. As in the OP, it would be convenient if one could simply hook into `zeros` and define

```julia
zeros(MyArray, Int, 2, 3)

```
