# Why does the following setindex call allocate?

**URL:** <https://discourse.julialang.org/t/why-does-the-following-setindex-call-allocate/100216>\
**Category:** Performance\
**Tags:** indexing, array\
**Created:** [June 12, 2023, 6:55am UTC](https://discourse.julialang.org/t/why-does-the-following-setindex-call-allocate/100216 "2023-06-12T06:55:23Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [June 12, 2023, 6:55am UTC](https://discourse.julialang.org/t/why-does-the-following-setindex-call-allocate/100216/1 "2023-06-12T06:55:23Z")

</div>

```julia
julia> function f!(v, A, r)
           v[eachindex(r)] = @view A[r]
           v
       end
f! (generic function with 1 method)

julia> v = zeros(10); A = ones(4,10);

julia> @btime f!($v, $A, 4:3:13);
  56.050 ns (2 allocations: 80 bytes)

julia> @btime f!($v, $A, 4:4);
  37.753 ns (2 allocations: 80 bytes)

```

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [June 12, 2023, 7:23am UTC](https://discourse.julialang.org/t/why-does-the-following-setindex-call-allocate/100216/2 "2023-06-12T07:23:36Z")

</div>

Seems likely that it allocates a subarray and fails to optimize it away. Cf

```julia
julia> g(v, A, r) = @view A[r]
g (generic function with 1 method)

julia> @btime g($v, $A, 4:3:13);
  11.263 ns (2 allocations: 80 bytes)

```

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [June 12, 2023, 7:53am UTC](https://discourse.julialang.org/t/why-does-the-following-setindex-call-allocate/100216/3 "2023-06-12T07:53:49Z")

</div>

This is also “strange”:

```julia
julia> g(A, r) = @view A[r]
g (generic function with 2 methods)

julia> A = reshape(1:(4*10),4,10)
4×10 reshape(::UnitRange{Int64}, 4, 10) with eltype Int64:
 1 5 9 13 17 21 25 29 33 37
 2 6 10 14 18 22 26 30 34 38
 3 7 11 15 19 23 27 31 35 39
 4 8 12 16 20 24 28 32 36 40

julia> B = collect(reshape(1:(4*10),4,10))
4×10 Matrix{Int64}:
 1 5 9 13 17 21 25 29 33 37
 2 6 10 14 18 22 26 30 34 38
 3 7 11 15 19 23 27 31 35 39
 4 8 12 16 20 24 28 32 36 40

julia> @btime g($A, $(4:2:13));
  10.065 ns (0 allocations: 0 bytes)

julia> @btime g($B, $(4:2:13));
  37.539 ns (2 allocations: 80 bytes)

```

---

<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:** [June 12, 2023, 9:14am UTC](https://discourse.julialang.org/t/why-does-the-following-setindex-call-allocate/100216/4 "2023-06-12T09:14:48Z")

</div>

> [@GunnarFarneback](#):
>
> Seems likely that it allocates a subarray and fails to optimize it away

But a SubArray shouldn’t be allocated in the first place. Unless you mean another Array that is a subset, but if that were to happen, I’d expect the reported amount of memory to vary by the slice’s length, but trying `4:2:13` and `4:1:13` still reports 80 bytes.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [June 12, 2023, 9:33am UTC](https://discourse.julialang.org/t/why-does-the-following-setindex-call-allocate/100216/5 "2023-06-12T09:33:05Z")

</div>

> [@Benny](#):
>
> But a SubArray shouldn’t be allocated in the first place.

```julia
 @view A[r]

```

That seems like it would create a SubArray, no?

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [June 12, 2023, 9:57am UTC](https://discourse.julialang.org/t/why-does-the-following-setindex-call-allocate/100216/6 "2023-06-12T09:57:46Z")

</div>

As far as I can trace it, the view does linear indexing into a 2D-array, which therefore needs to be reshaped into a vector, which eventually lands in [julia/reshapedarray.jl at master · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/blob/master/base/reshapedarray.jl#L51) and the `ccall` needs to allocate memory.

---

<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:** [June 12, 2023, 10:15am UTC](https://discourse.julialang.org/t/why-does-the-following-setindex-call-allocate/100216/7 "2023-06-12T10:15:04Z")

</div>

Oh now I notice the view/SubArray’s parent has a different type. The linear indexing `reshape`d a `Matrix`, and it allocated a `Vector` instead of wrapping the `Matrix` in a `ReshapedArray`. The allocated memory doesn’t vary with slice length because the `Vector` and the `Matrix` share the same buffer.

```julia
julia> time_view(A, I) = @time @view(A[I]);
julia> A = ones(4,10); x = time_view(A, 4:3:13)
  0.000004 seconds (2 allocations: 80 bytes)
4-element view(::Vector{Float64}, 4:3:13) with eltype Float64:
 1.0
 1.0
 1.0
 1.0
julia> typeof(reshape(A, length(A)))
Vector{Float64} (alias for Array{Float64, 1})
julia> Base.mightalias(x.parent, A)
true
julia> x.parent[1] = 0; (x.parent[1], A[1])
(0.0, 0.0)

```

Wonder why it works this way though. A `Matrix` can be linearly indexed directly, so it seems fine as a parent for `ReshapedArray`. Why choose the overhead of heap-allocating an aliased `Vector`?

```julia
julia> time_oddview(A, I) = @time view(Base.ReshapedArray(A, (length(A),), ()), I);
julia> A = ones(4,10); x = time_oddview(A, 4:3:13)
  0.000002 seconds
4-element view(reshape(::Matrix{Float64}, 40), 4:3:13) with eltype Float64:
 1.0
 1.0
 1.0
 1.0

```
