# Allocation when assigning to a slice

**URL:** <https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381>\
**Category:** General Usage\
**Tags:** memory-allocation\
**Created:** [December 20, 2021, 4:30pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381 "2021-12-20T16:30:59Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![etienne\_dg](https://avatars.discourse-cdn.com/v4/letter/e/fbc32d/32.png) [@etienne\_dg](https://discourse.julialang.org/u/etienne_dg)\
**Post date:** [December 20, 2021, 4:30pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/1 "2021-12-20T16:30:59Z")

</div>

Hi,  
Why does the second version allocate ? Is there a clean way to do that without allocating ?

```julia
z = collect(1:10000)

function test1(z)
    z .-= 1
end
4.898 μs (0 allocations: 0 bytes)

function test2(z)
    z[56:end] .-= 1
end
20.458 μs (3 allocations: 77.84 KiB)

function test3(z)
    for i in 56:length(z)
        z[i] -= 1
    end
end
14.115 μs (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [December 20, 2021, 4:35pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/2 "2021-12-20T16:35:18Z")

</div>

> [@etienne\_dg](#):
>
> ```julia
> function test2(z)
> @view(z[56:end]) .-= 1
> return z # otherwise the slice is returned
> end
> 
> ```

solves the allocations (although I think that shouldn’t be necessary)

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 20, 2021, 4:37pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/3 "2021-12-20T16:37:36Z")

</div>

> [@lmiq](#):
>
> (although I think that shouldn’t be necessary)

It’s totally necessary, because:

```julia
z[56:end] .-= 1

```

is equivalent to

```julia
z[56:end] .= z[56:end] .- 1

```

and the slice `z[56:end]` on the right-hand side [allocates a copy](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-views).

I also find it a lot clearer in most cases to just put `@views` on the whole function rather than on individual lines.

```julia
@views function test4(z)
    z[56:end] .-= 1
end

```

giving

```julia
julia> @btime test4($z);
  1.681 μs (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [December 20, 2021, 4:39pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/4 "2021-12-20T16:39:00Z")

</div>

> [@stevengj](#):
>
> is equivalent to
> 
> ```julia
> z[56:end] .= z[56:end] .- 1
> 
> ```

Why not to

```julia
z[56:end] .= @view(z[56:end]) .- 1

```

which does not allocate? That is my point, in general the syntax is such that slices on the left do not create copies.

---

<div class="post-metadata">

**Author:** ![etienne\_dg](https://avatars.discourse-cdn.com/v4/letter/e/fbc32d/32.png) [@etienne\_dg](https://discourse.julialang.org/u/etienne_dg)\
**Post date:** [December 20, 2021, 4:39pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/5 "2021-12-20T16:39:12Z")

</div>

Thanks for the insightful answer

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [December 20, 2021, 4:39pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/6 "2021-12-20T16:39:30Z")

</div>

> [@stevengj](#):
>
> It’s totally necessary, because:
> 
> ```julia
> z[56:end] .-= 1
> 
> ```
> 
> is equivalent to
> 
> ```julia
> z[56:end] .= z[56:end] .- 1
> 
> ```

this feels like an optimization we should do since this is pretty annoying if not counter intuitive

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 20, 2021, 4:39pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/7 "2021-12-20T16:39:42Z")

</div>

> [@lmiq](#):
>
> Why not to
> 
> ```julia
> z[56:end] .= @view(z[56:end]) .- 1
> 
> ```

Because `A -= B` in Julia has always been equivalent to `A = A - B`, and `.-=` is the same?

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [December 20, 2021, 4:43pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/8 "2021-12-20T16:43:04Z")

</div>

> [@stevengj](#):
>
> Because `A -= B` in Julia has always been equivalent to `A = A - B` , and `.-=` is the same?

Of course that is an argument, but slices on the left are different, so that could be different as well. But it may be that parsing that becomes impossible when one goes to more general cases.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 20, 2021, 4:44pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/9 "2021-12-20T16:44:39Z")

</div>

> [@jling](#):
>
> this feels like an optimization we should do

It would be a breaking change. e.g. it would change the answer in:

```julia
x = [3,2,1]
x[1:2] .-= sort!(x)[1:2]

```

There was a long debate early in the history of Julia about whether we should change slices to default to views ([range indexing should produce a subarray, not a copy · Issue #3701 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/3701)). Ultimately it was decided not to change because (a) attempting to change the default turned out to be a source of too many subtle breaking bugs, (b) it wasn’t always a performance win, and (c) the introduction of `@views` made it relatively painless to opt-in for a large block of code, e.g. a whole function.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [December 20, 2021, 4:47pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/10 "2021-12-20T16:47:55Z")

</div>

Simpler one:

```julia
julia> x = [1,2,3]
3-element Vector{Int64}:
 1
 2
 3

julia> x[2:-1:1] .= @view(x[1:2])
2-element view(::Vector{Int64}, 2:-1:1) with eltype Int64:
 1
 2

julia> x[2:-1:1] .= x[1:2]
2-element view(::Vector{Int64}, 2:-1:1) with eltype Int64:
 2
 1

```

(and not only breaking, but possibly completely unpredictable 🙂 ).

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 20, 2021, 4:52pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/11 "2021-12-20T16:52:26Z")

</div>

That being said, it’s possible that the compiler could at some point recognize that it can safely replace copies with views in _certain_ cases, as commented by @StefanKarpinski [here](https://github.com/JuliaLang/julia/issues/3701#issuecomment-320043096). Doing so would probably privilege “built-in” array types and functions that the compiler can analyze easily, however, and the design of Julia has always favored optimizations (e.g. loop fusing for dot operations) and syntax (e.g. `@views`) that apply equally well to user-constructed types and functions.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [December 20, 2021, 10:47pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/12 "2021-12-20T22:47:14Z")

</div>

I feel like the at least literal values on the rhs of ` .+=` should be optimized. Even if we just do a patchy work in, say, parser/lowering stage would be helpful.

Hard case that requires analysis in compiler passes can be deferred

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [December 21, 2021, 9:18pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/13 "2021-12-21T21:18:47Z")

</div>

There’s not much that can be special-cased for array literals during lowering since `vect` is just a generic function.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 21, 2021, 9:23pm UTC](https://discourse.julialang.org/t/allocation-when-assigning-to-a-slice/73381/14 "2021-12-21T21:23:06Z")

</div>

> [@jling](#):
>
> I feel like the at least literal values on the rhs of ` .+=` should be optimized.

I find it hard to believe that `array .+= literal` is a performance-critical step in much real-world code, to the point of being worth special-casing in the compiler.
