I’m currently going through this excellent book on getting started with Julia, and I’ve run into a behavior I don’t quite understand. The book provides this example of a function that overwrites its inputs:

function addone!(a)
for i in 1:length(a)
a[i] += 1
end
end

Now any input gets overwritten by adding one to it:

julia> x = [1 2 3];
julia> addone!(x);
julia> x
1×3 Matrix{Int64}:
2 3 4

Above, we see that every element of x now has 1 added to it.

To me, the loop in the function above looks like just an unnecessary bit of clutter, so I attempted to rewrite the function as follows:

function my_addone!(a)
a = a .+ 1
end

Now when I try to use my_addone! in the same way that I used addone! above, I find that the behavior is different:

julia> x = [1 2 3];
julia> my_addone!(x);
julia> x
1×3 Matrix{Int64}:
1 2 3

Why is it that the function only overwrites the input if there’s a loop inside the function? I feel like I’m missing some fundamental principle.

With the dot above, the a .= a .+ 1 is a syntax sugar for the same loop of the original function. Without the dot, a = a .+ 1 creates a new array from the result of a .+ 1 (with the elements with 1 added), but assigns that label a to this new array. The fact that the label a was “taken” does not matter here, that is equivalent to b = a .+ 1 where b is the label of the newly created array.

Many thanks, @oheil and @lmiq! Your explanations are very clear.

I see that my attempt with = was just making a copy that happened to have the same name as the input a, whereas .= is shorthand that overwrites each element of a. Very cool!