Static arrays being mutated, what is going on?

I do not understand how v3 is the code below is being allowed to mutate. What is going on there?

using StaticArrays
using BenchmarkTools

function test(v1, v2)
    v3 = zeros(SVector{3,Float64})
    for i in 1:10^4
      v3 = (v1 .* v2) .+ v3
    end
    v3
end

v1 = rand(SVector{3,Float64});
v2 = rand(SVector{3,Float64});

test(v1,v2)

@btime test($v1,$v2)

And it does not allocate anything (which also surprises me, as I thought at least that v3 should have been allocated ,it is allocated in the stack and, thus, do not count? )

julia> @btime test($v1,$v2)
  10.025 ÎĽs (0 allocations: 0 bytes)
3-element SArray{Tuple{3},Float64,1,3} with indices SOneTo(3):
 5655.280099799662
  761.1553139585608
 1664.2491656557113


They are not mutated, each subsequent v3 is a new value, not unlike an integer or a float (hence the lack of allocation).

3 Likes

Yes, StaticArrays are allocated on the stack (because their size is known) and therefore don’t “count”.

v3 isn’t actually mutated. v3 = (v1 .* v2) .+ v3 creates a new vector and binds v3 to it. v3 old bind is thrown away.

Edit: to make it more clear: the array that is bound to the name v3 isn’t mutated, it’s exchanged for a whole new array, which is bound to the name v3 instead.

3 Likes

The any integer analogy is very good, thanks.

The fact that this is not possible (and if with a mutable vector, slower) is something that I have to get familiar with:

function test(v1, v2)
    v3 = zeros(SVector{3,Float64})
    for i in 1:10^4
      for i in 1:3
        v3[i] = (v1[i] * v2[i]) + v3[i]
      end
    end
    v3
end

Uhm… this works (and is fast):

julia> v = [ rand(SVector{3,Float64}) for i in 1:10_000 ];

julia> function sumv!(v)
         for i in 2:length(v)
           v[i] = v[i] + v[i-1]
         end
       end
sumv! (generic function with 1 method)

julia> sumv!(v)

Now I see many other ways of using StaticArrays… I was thinking that they were much more limited.