I have a C based mental model of what is happening. Can anyone comment on whether it is correct?
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?
I don't mean to criticize. I think the best advice is to read K&R C again. And, as some other posters have suggested, take a look and at least a passing understanding of the memory model and assembly code generated by C/C++ compilers.
You'll see, for instance, that type information is not stored as a field in a C struct at all, it's purely a distinction for the compiler to use. A C struct, indeed any type of data in C, is _just_data_ in memory. At the machine level, there's no such thing as a type. Just registers, memory, and instructions. The compiler uses type information to generate the right instructions to handle the type.
And to clarify, type metadata _as_actual_data_ can exist in higher level languages, but it's definitely not a C thing.
Comments
I have a C based mental model of what is happening. Can anyone comment on whether it is correct?
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?
This is really far off, actually.
I don't mean to criticize. I think the best advice is to read K&R C again. And, as some other posters have suggested, take a look and at least a passing understanding of the memory model and assembly code generated by C/C++ compilers.
You'll see, for instance, that type information is not stored as a field in a C struct at all, it's purely a distinction for the compiler to use. A C struct, indeed any type of data in C, is _just_data_ in memory. At the machine level, there's no such thing as a type. Just registers, memory, and instructions. The compiler uses type information to generate the right instructions to handle the type.
And to clarify, type metadata _as_actual_data_ can exist in higher level languages, but it's definitely not a C thing.
I was speaking of a model of how python does things, based on a C style implementation. Not an explanation of how C works.
That is more or less correct. It isn't exactly what happens, but the mental model is correct.