Understanding in-place broadcasting syntax (.=)

I guess the dot in front of the equal sign is a typo?

1 Like

No, it is correct, and required to make the operation work in-place.

3 Likes

Ok, this notation is not easy to understand for a beginner. Here my code snippet to understand better:

array = [1 2.0 3.3; 2.0 7.0 -1.3]; array_A = copy(array)
array_A .= clamp.(array_A, -1.0, 6.0)
array_B  = clamp.(array, -1.0, 6.0)
array_C .= clamp.(array, -1.0, 6.0)   # ERROR: UndefVarError: array_C not defined

When you write x[1] = 1 or y[:] = [1,2,3], you depend on x and y already being defined as arrays and you’re simply mutating their stored values.

Writing z .= [1,2,3] is similar. It looks deceptively similar to z = [1,2,3], but they’re two different things: the former updates the stored values in-place, while the latter (re)assigns the identifier entirely.

3 Likes

@uniment And I guess the in-place operation saves time and memory for large arrays?

Small arrays too :wink:

Performance tips - pre-allocating outputs

If you struggle with the dots, I often prefer the equivalent map and map! which can make the in-place intent a little more explicit.

In this case, it would be written as:

map!(array, array) do x
    clamp(x, lo, hi)
end
1 Like

In fact, if the array in question is one where the first axis is much smaller than the trailing ones, such as a wide matrix with a handful of rows, then in-place broadcasting can be much slower than map!

1 Like

Except for DataFrames :crazy_face: (see What if `df.col .= v` was in-place?)

1 Like

image