# Error calling \`similar(Array{ComplexF32}, Float32)\`

**URL:** <https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248>\
**Category:** Internals & Design\
**Tags:** documentation, bug, base\
**Created:** [August 24, 2022, 8:25am UTC](https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248 "2022-08-24T08:25:43Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [August 24, 2022, 8:25am UTC](https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248/1 "2022-08-24T08:25:43Z")

</div>

writing code that is agnostic about the array type but can still change the element\_type, one wants to keep the array type but change the element-type for example to real(eltype(ArrayType)) for efficiency reasons.  
The function `similar()` claims to provide just this according to the documentation. However, this feature seems to work only for instances but not for types. I.e.

```julia
A = Array{ComplexF32}
similar(A(undef, 0), real(eltype(A)))

```

is fine, whereas

```julia
A = Array{ComplexF32}
similar(A, real(eltype(A)))

```

causes an error (tested on Julia Versions 1.7.1 and 1.8.0).  
Maybe this could be in the documentation or changed in the next Julia Version?

---

<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:** [August 24, 2022, 9:59am UTC](https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248/2 "2022-08-24T09:59:45Z")

</div>

We could do something like the following.

```julia
julia> Base.similar(::Type{A}, ::Type{S}) where {T, A <: Array{T}, S} = Array{S}

julia> similar(Array{ComplexF64},Float64)
Array{Float64}

```

Perhaps someone could make this even more generic.

I’m trying to decide is this should still be `similar`.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [August 24, 2022, 10:14am UTC](https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248/3 "2022-08-24T10:14:11Z")

</div>

Creating an “similar” array from the original type and a new eltype or size would be a very useful feature. Without it, for example, it’s not possible to implement `reduce(vcat)` or `stack` that would work for empty arrays.  
However, this feature isn’t implemented in julia for now.

---

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [August 24, 2022, 10:52am UTC](https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248/4 "2022-08-24T10:52:37Z")

</div>

> [@mkitti](#):
>
> `Base.similar(::Type{A}, ::Type{S}) where {T, A <: Array{T}, S} = Array{S}`

Great way of doing this! Much nicer than my hacky implementation:

```julia
function get_real_arr_type(::Type{TA}) where {TA}
    typeof(similar(TA(undef, ntuple(x->0, ndims(TA))), real(eltype(TA))))
end

```

---

<div class="post-metadata">

**Author:** ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)\
**Post date:** [August 24, 2022, 12:55pm UTC](https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248/5 "2022-08-24T12:55:26Z")

</div>

I seem to recall that @StefanKarpinski once suggested generalising our current idiom for creating uninitialized arrays. Something like `ArrayType{ElementType}(value, dims...)` which cleanly separates out the four different concerns. The same pattern could be extended for zero initialisation and such.

If that general pattern was implemented, you could to `typeof(MyArray){Float64}(undef, size(MyArray))`. In fact, that might already work, depending on your array type.

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [August 24, 2022, 1:58pm UTC](https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248/6 "2022-08-24T13:58:21Z")

</div>

> [@jakobnissen](#):
>
> typeof(MyArray){Float64}(undef, size(MyArray))

This seems like strange syntax, as it’s going to have two type parameters, the second of which becomes the eltype. At the moment that’s an error:

```julia
julia> x = StructArray(MtlArray(rand(Float32, 3)).+im);

julia> similar(x, Int32, (1, 4))
1×4 MtlArray{Int32, 2}:
 0 0 0 0

julia> typeof(x)
StructVector{ComplexF32, NamedTuple{(:re, :im), Tuple{MtlArray{Float32, 1}, MtlArray{Float32, 1}}}, Int64} (alias for StructArray{Complex{Float32}, 1, NamedTuple{(:re, :im), Tuple{MtlArray{Float32, 1}, MtlArray{Float32, 1}}}, Int64})

julia> typeof(x){Int32}
ERROR: TypeError: in Type{...} expression, expected UnionAll, got Type{StructVector{ComplexF32

```

It’s for complicated wrapped types that `similar` is so useful, and (IMO) the extension to accept the type not an instance seems pretty natural.

---

<div class="post-metadata">

**Author:** ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)\
**Post date:** [August 24, 2022, 2:08pm UTC](https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248/7 "2022-08-24T14:08:25Z")

</div>

Ah yes, you are right about the extra type parameter. Yeah, perhaps this is the role of similar. Although in this case it sounds like it should be a constructor? I mean “How do I make an instance given a type and its parameter” sounds like the definition of a constructor for me.

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [August 24, 2022, 3:02pm UTC](https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248/8 "2022-08-24T15:02:38Z")

</div>

Yes as a generalisation of constructors like `Array{Int}(undef, 3)` to fill with other values, this sounds fine.

I guess `similar(::Type, size...)` is very close to being a constructor. The types must match (e.g. you can’t even change ndims, `similar(typeof([1,2,3]), (4, 5))` is an error) and it doesn’t exist for many wrapped types like `similar(typeof([1,2,3]'), (1, 5))`. I’m not sure why it exists, in addition to `Array{T}(undef, ...)`.

But `similar(instance, eltype, size...)` often makes something which is _not_ of the type of the first argument, and usually recurses into complicated types. I wonder if there is any obstruction to generalising it to accept the type… does the type always give you enough information? Maybe it doesn’t indicate (say) which of several GPUs an object lives on?

---

<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:** [August 24, 2022, 5:42pm UTC](https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248/9 "2022-08-24T17:42:38Z")

</div>

Here’s a slight improvement. I’m not very convinced that this should be called `similar`, so I’ll call it `seteltype` for now.

```julia
seteltype(::Type{<: Array{T,N} where T}, ::Type{S}) where {S,N} = Array{S,N}
seteltype(::Type{<: Array}, ::Type{S}) where {S} = Array{S}

```

Here’s a demonstration.

```julia
julia> seteltype(Array, Float64)
Array{Float64}

julia> seteltype(Array{Int}, Float64)
Array{Float64}

julia> seteltype(Array{Int,5}, Float64)
Array{Float64, 5}

```

---

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [August 25, 2022, 6:53am UTC](https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248/10 "2022-08-25T06:53:31Z")

</div>

I see that the implementations of @mkitti contain the final type `Array`, which is not really what I intended it to be, yet it is debatable. E.g. `similar(CuArray(1:10), Float32, 5)` yields a 5-element `CuArray{Float32}` and not `Array{Float32}`.  
I would prefer that `similar(CuArray{Int64}, Float32, 5)` yields also a 5-element `CuArray{Float32}`.  
This could be implemented as follows:

```julia
function replace_eltype(::Type{TA}, ::Type{S}, num_dims=1) where {TA<:AbstractArray, S}
    typeof(similar(TA(undef, ntuple(x->0, num_dims)), S))
end

Base.similar(::Type{A}, ::Type{S}, dims) where {T, A <: AbstractArray{T}, S} = (replace_eltype(A, S, length(dims)))(undef, dims)

```

but its not a very nice implementation. If there was a Metaprogramming way to access the wrapping array-type, this may be implemented in a much nicer way.  
Another bad part of this implementation is, that it does not allow the user the change the number of dimensions. I.e. `similar(CuArray{Int, 2, CUDA.Mem.DeviceBuffer}, Float32, 6)` yiels an error, whereas `similar(CuArray{Int, 1, CUDA.Mem.DeviceBuffer}, Float32, 6)` works.

But I guess the main question is, whether it is a good idea to assume by default that arrays are mutable or whether the default should indeed (as in @mkitti 's implementation) go to the type `Array` but then implementers of mutable arrays need to always care for this case individually.

---

<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:** [August 25, 2022, 3:08pm UTC](https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248/11 "2022-08-25T15:08:44Z")

</div>

The issue is that not all `AbstractArray`s necessarily have two parameters in the order we expect. I think it might be good to do this explicitly for each concrete `AbstractArray` implementation.

We could make some code to generically replace the first parameter of a type without any guarantees that it is actually the element type.

Another approach might be a parameter substitution approach e.g. swap `Int64` for `Float64`.

---

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [August 30, 2022, 10:18am UTC](https://discourse.julialang.org/t/error-calling-similar-array-complexf32-float32/86248/12 "2022-08-30T10:18:12Z")

</div>

I see. I guess, you mean the parameters of the type (written in curly brackets), which makes a lot of sense. But then the original way of implementing it via an empty array, is maybe not such a bad solution. It exploits that every implemented array should have a `similar` implemented and it makes sense that the type is then propagating the same way. Here is a slightly more complete solution which also works for `AbstractArray`s that do not have a dimension specified. See the implementation here:

> <https://github.com/bionanoimaging/NDTools.jl/blob/main/src/type_tools.jl>

These functions return a similar array type but using as TA, but eltype and ndims can be changed.  
Does it make sense to have something like this in `Base`?
