Assignment and mutation

Subtle differences between assignment and mutation in Julia as shown in the script below are easy to be missed or misunderstood by a beginner like me. I’m starting to understand and realize the importance, but still not really confident. If there’s a good (clear, plain, accurate and concise) document on the issue for beginners, I really appreciate a pointer to it.

In the script below, temp(a) has an assignment, and temp1(a) a mutation. The difference is just a dot, and the results look the same [4,5,6]. It’s hard for a beginner to realize they are actually different arrays. Interestingly, temp1(a) allocates more than six times of memory than temp(a) and slower (true when @benchmark is used).

temp2(a) is same as temp1(a) except it returns nothing. It has smaller allocation and faster execution than the other two functions.

I was naively using functions like temp(a), but realize that I should use functions like temp2(a) as temp!(a) when I mean mutation of the array a. Is this thinking correct?

a = [1,2,3];
function temp(a)
    a = [4,5,6]
end
function temp1(a)
    a .= [4,5,6]
end
function temp2(a)
    a .= [4,5,6]
    return nothing
end
temp2 (generic function with 1 method)
@time a1 = temp(a)
  0.007462 seconds (3.14 k allocations: 163.691 KiB)





3-element Array{Int64,1}:
 4
 5
 6
@time a2 = temp1(a)
  0.056520 seconds (20.21 k allocations: 1.006 MiB)





3-element Array{Int64,1}:
 4
 5
 6
a == a1 == a2
true
a === a1
false
a === a2
true
a = [1,2,3]
3-element Array{Int64,1}:
 1
 2
 3
@time temp2(a)
  0.005079 seconds (217 allocations: 12.904 KiB)
a
3-element Array{Int64,1}:
 4
 5
 6
3 Likes

Maybe this is a good read: Values vs. Bindings: The Map is Not the Territory · John Myles White

3 Likes

Perhaps this will help as well: Primitive and Composite? Types - #7 by rdeits

3 Likes

The simplest version of this I can come up with is this:

  • Assignment changes which object a name refers to: x = ex causes the name x to refer to the value resulting from the evaluation of the expression ex. Assignment never changes the values of any objects.

  • Mutation changes the value of an object: x[i] = ex and x.f = ex both mutate the object referred to by x changing a value at index or a property with a name, respectively. Mutation never changes what objects any names in any scope refer to.

Perhaps the confusion comes from the fact that these all use the = in their syntax? They’re really totally unrelated. It’s also possible that people think of assignment as setting a named property on some implicit “scope object”. That’s probably a view that can be worked out coherently, in which case having a clear notion of what all the different “scope objects” are would be crucial but I’m not entirely sure if that’s a helpful way to think about the matter or not.

6 Likes

Thanks for the pointer.

I needed to know how to make sure an array in a function was mutating, not copying when I used it thousands of times repeatedly. Because copying increases allocation and tons of garbage collection tend to make it slow.

Thank you for a nice and helpful explanation.

The meaning of “=” is indeed ambiguous sometimes, not only in programming languages, but also in mathematics. Even “abused” in a sense…

In R, “<-” is used for assignment. So, an operation like temp(a ← a + 1) is possible. In Julia, temp(a = a + 1) has a different meaning. In Mathematica, “=:” is used for definition, for example. It uses “->”, too. In Matlab,…

I like Julia’s syntax enabling users to write code following math (… there’s a nice word for it…I forgot). It’s quite obvious how important syntax or notation in math. But, I can view the language like Julia not only as following the math, but also extending the math in a sense. The concept of multiple dispatch, for example, is very common in math, but Julia’s extensive, systematic and contextual use of it made it much more general. In a sense, it’s extending math… In that sense, Julia can even clarify and correct ambiguous syntax/notation existing in math for some historical reasons.

1 Like

There is a trade-off between keeping the syntax convenient and clearly demarcating various semantics. In a sense, .= extends the broadcasting syntax naturally to assignment.

I think you may find it neat when you get used to it, but if you carry over intuition from other languages it is true that you can run into surprises. I would recommend working through the manual (not reference or the developer docs, just the first part).

1 Like