In C terms, I think of all objects (including primitives such as numbers) as a struct with a void* pointer that holds the actual data, and another field that describes how to interpret the data: struct Obj { void* data; ObjDesc descr; }
Whenever you do objA=objB you create an new struct Obj with objA.data == objB.data. The same things happens when you pass an object to a function: you create a copy of the Obj.
When you modify an Obj, two things can happen: if the Obj is immutable you change where void* data points to: n1 = 4 n2 = b1 n1 = 5 ==> n1.data != n2.data
On the other hand, if Obj is mutable, than you don't change void* data, you modify the memory pointed to by data: n1=[] n2=n1 n1.append(1) ==> n1.data == n2.data
Is this correct or is mental model going to bite me sometime?