Functions with a bang!

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.

No worries, you did well. You just missed a little dot:

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

will do.

I thought I find a section about why your version copies the result, but I didn’t found it. So I just tell you that

a .+ 1

creates a new array, which is than assigned to a. … aah I give up, @lmiq does a better job :wink:

2 Likes

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.

6 Likes

The best source of info about that is probably this post: More Dots: Syntactic Loop Fusion in Julia

3 Likes

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!

2 Likes

To contribute nothing more than a name, this behaviour is called variable shadowing.

3 Likes