On Nov 7, 2019, at 01:04, Martin Euredjian via Python-ideas <email@example.com> wrote:
>> No professional thinks that "a = some_object" results in a bucket being filled with whatever the object might contain.
> That's exactly how variables work in many common languages like C
Nope, not true. Bytes, words, integers and that's about it. Anything else is a pointer to a relevant data structure somewhere in memory. I think I can say this it true of the vast majority of languages. Exceptions are cases like Python and, say, Objective-C, or, in general, where the philosophy is that everything is an object. Nobody is filling buckets with anything every time there's an assignment, at least no language I have ever used.
Almost every part of this is seriously wrong.
In C, filling a struct-shaped bucket with a struct-shaped value is exactly what happens when you initialize, assign to, or pass an argument to a struct-typed variable. Early C severely restricted when you could do such things, but that’s always how it worked when it was allowed, and in modern C it’s allowed almost everywhere you’d want it to be. If you want to pass around a pointer in C, you have to be explicit on both ends—use a pointer-to-struct-typed variable, and use the & operator on the value (and then you have to use the * operator to do anything with the pointer variable). And the right way to think about it is not reference semantics, but filling a pointer-shaped bucket with a pointer-shaped value. (Or, actually, not just “pointer” but specifically “pointer to some specific type”; you can’t portably stick a pointer-to-nullary-int-function value in a pointer-to-double value.)
And this is key to the whole notion of lvalue semantics, where variables (among other things) are typed buckets with identity for storing values (that are just bit patterns), as opposed to namespace semantics, where variables (among other things) are just names for typed values with identity that live wherever they want to live. After `a=b` in a namespace language, `a is b` is true, because a and b are two names for the one value in one location; in an lvalue language, there usually is no such operator, but if there were. `a is b` would still be false, because a and b are two distinct locations that contain distinct copies of the same value, because what `a=b` means is filling the a bucket with the value in the b bucket. (In fact, in C., even `a==b` might not be true if, say, `a` is an uint16 variable and b is a uint32 variable holding a value over 65535.)
And it’s not like lvalue semantics was a dead-end bad idea from C that other languages abandoned. C++ took lvalue semantics much further than C, and built on struct assignment with notions like assignment operators, that let your type T customize how to fill a T-shaped bucket with whatever kind of value you want. C# and Swift built even further on that by syntactically distinguishing value types (that act like C structs) and reference types (that act sort of like Python objects).
Meanwhile, while most “everything is an object” languages like Python, Smalltalk, and Ruby (but not Objective C, which is about as far from everything-is-an-object as possible) use namespace semantics, they’re hardly the only languages that do; so do, for example, plenty of impure functional languages that aren’t at all OO.
Meanwhile, “bytes, words, integers, and… anything else is a [implicit] pointer” is a kind of clunky manual optimization used in various 80s languages, and borrowed from there into Java, but much less common in newer languages. It’s hardly a universal across languages, much less some kind of a priori necessity.