Why it does not modify vector in place


I was confused with the following function that modify the vector “as a whole” v.s. the link https://docs.julialang.org/en/v1/manual/performance-tips/index.html#Pre-allocating-outputs-1. My function does not change the vector. Why will it behave differently?

Thank you everybody for the help.

a = randn(100)
copy_of_a = copy(a)
function modified!(a, copy_of_a)
    a = randn(100)
    sum(a .!= copy_of_a) #inside the function it was modified
modified!(a, copy_of_a)
sum(a .!= copy_of_a) #but outside the function a still is the original

Your function is binding the symbol a to a new array, not mutating the outside one. Here’s a way to see it:

julia> @show a[1] objectid(a); # old
a[1] = 0.9312276078859445
objectid(a) = 0x0835e8e05a663b75

julia> function modified!(a, copy_of_a)
           @show a[1] objectid(a) # old
           a = randn(100)
           @show a[1] objectid(a) # new
           sum(a .!= copy_of_a) #inside the function it was modified
modified! (generic function with 1 method)

julia> modified!(a, copy_of_a)
a[1] = 0.9312276078859445
objectid(a) = 0x0835e8e05a663b75
a[1] = 0.18746827198090105
objectid(a) = 0x828f4d79978ef50d

If you wrote a .= randn(100) or copyto!(a, rand(100)), or just a .= randn.(), then instead the values inside a would be altered.


Thank you. That makes sense. But I still have some confusion.

  1. Why it decided to make a new local variable instead of mutate in place as element-wise operation?
  2. The way you pointed out a .= randn(100), will that allocate an array for randn(100) first? Then element wise assigns to a?

This avoids allocating the temporary for randn while modifying the Vector{Float64}(undef, 100):

Vector{Float64}(undef, 100) .= randn.()
1 Like

The explanation in the FAQ may solve your confusion:


Yes, if you want to avoid allocation of a vector as great as a on the right hand side, you can loop over the values of a.


You could also do a .= randn.() or (equivalently) @. a = randn()