Steve D'Aprano <steve+pyt...@pearwood.info> writes: > On Thu, 17 Aug 2017 11:37 pm, Ben Bacarisse wrote: > >> What goes wrong when someone thinks of Python as passing by value but >> the value of an expression is an object reference?
This seems to be a hot-button topic so I'd like to try to cool it off a bit. To in that spirit I'll point out that I'm not advocating teaching "the wrong way to think about things", I'm asking if that model, universally applied, actually leads to misunderstanding Python. > Lots. > > Because even if people *think* about call by value where the value is an > invisible reference to the actual value, that's not how they talk, because > it's > too hard. People will drop the word reference (I prefer identity) on occasion but then they are always going to take shortcuts. > Look at Scott Stanchfield's extremely influential post. It is *not* > called: > > "Java is call by value where the value is an invisible object reference, > dammit!" > > http://javadude.com/articles/passbyvalue.htm > > and consequently people who don't read or understand the *entire* post in full > take away the lesson that > > "Java is call by value, dammit!" I don't think this is a fair point. You will run out of ideas if they are to be avoided because some people will get the wrong idea when reading part of a description of that idea applied to some other language. > So how do we distinguish between languages like Java and Python and > those like C and Pascal which *genuinely* are call by value, and do > exhibit call by value semantics? For example, in Pascal, if you > declare an array parameter without specifying it as "var", the > compiler will copy the entire array. Java does not do that. Python > does not do that. Well, I know how I do that but you are not a fan of that view. I found it a helpful view because it covers a lot more than just argument passing by saying something about the set of values that Python expressions manipulate. It may be wrong in some case (hence my question) but I don't think I've been led astray by it (so far!). > C doesn't treat arrays as first class values, so you can't pass an array as > argument. You can only pass a pointer to the start of the array. But you can > declare arbitrarily big structs, and they are copied when you pass them to > functions. Java objects are not. Despite Scott's insistence that Java is > exactly the same as C, it isn't. I'm not here to defend someone else's incorrect statements! Clearly C is not the same as Java. Equally clearly, C only passes arguments by value (I have no idea about Java). > If we claim that Python is call by value, without specifying the > proviso "if you consider the value to be the invisible reference to > the actual value" every time, we risk misleading others into wrongly > inferring that Python is "call by value" and you shouldn't pass big > lists to functions because then they will be copied and that's > inefficient. True, though I obviously take issue with using a particularly long-winded phrase. See later for how Liskov does it with one short word. The core of the idea is actually what the value-set of Python programs is -- the passing by value just drops out of that. Talking about object identities (or references) is not so very cumbersome. You have to talk about *something* like that explain the language, don't you? > Or people will be confused by the behaviour of Python, and decide that maybe > it > is only call by value when you pass an immutable object like a string or int, > and is call by reference when you pass a mutable object like a list or dict. > Many people have done that. I'm not a fan of this notion that an idea is bad because it goes wrong when people don't understand it. I don't think any description of Python's semantics can avoid that trap. > Imagine this conversation: > > * * * > > "I was reviewing your code, and in module spam.py I don't understand what > value > the x variable has." > > "I don't know. It's something implementation dependent." > > "What do you mean?" > > "It depends on the interpreter. In CPython the value will be a pointer. > Something like an address 0x1234abcd." > > "But Python doesn't have pointers." > > "Okay, call it a reference then. Whatever the implementation uses to point to > objects." > > "I don't care about the Python implementation, I want to know the value of x." > > "I told you. It's some unknown and unknowable reference or pointer to an > object." > > "Okay. Given x=1, what's the value of x?" > > "How do I know? It depends on the implementation. Something like 0x93a80f16 I > guess. Why do you care about the value?" > > > * * * > > Obviously this isn't going to happen. Nobody actually thinks like > this. No, I should hope not! > Given > x=1, we all agree that the value of x is 1, not some invisible, unknown, > unknowable, implementation-dependent reference. > > Instead they have to juggle two mutually contradictory meanings of value in > their head, and try to guess which one is meant at any point. Sometimes the > value of x is 1, and sometimes it is the invisible reference, and because that > is usually implied rather than explicit, there's always room for confusion and > misunderstanding. > > This whole thing is unnecessary. It is no easier to learn that: > > "Python is call by value, where the value is an invisible object reference" > > than it is to learn that: > > "Python is call by object sharing". I'm not advocating the former because I want to say more than just what values get passed, and the latter does not explain some other cases that confuse people new to the language such as x = [[1]] y = x x[0][0] = 42 I find that keeping in mind (despite the odd shortcut I may make) that all these values really just /refer/ to objects helps me. > Either way, you have to learn what it means, otherwise it might as well be > gobbledygook: > > "Python is whargle bargle by wazit, where the wazit is fizzbit wacker > p'toing". > > > The terminology has been around for forty years. It was invented by > Barbara Liskov, one of the pioneers of OOP, the same person > responsible for the Liskov Substitution Principle. So its not like it > is some obscure term invented by "just some guy on the internet". Yes I know. I had the pleasure of talking programming languages with her once -- scary bright person! Liskov on CLU: x := e causes x to refer to the object obtained by evaluating expression e. Not the "refer". That's all it takes. The value of x is not the object, x /refers/ to the object. And on calling: ... arguments are passed "by object"; the (pointer to the) object resulting from evaluating the actual argument expression is assigned to the formal. (Thus passing a parameter is just doing an assignment to the formal.) I think this is true of Python too. If so, I'd be tempted to define passing "as if by assignment" (as it's done in the C standard) and make the semantics of assignment the basic feature that needs to be described. Finally, from the Python tutorial[1] "... arguments are passed using call by value (where the value is always an object reference, not the value of the object)." Maybe I got it from there and generalised a little. I would not want to see that remark removed (because, if that's where I got it from, it helped me), but maybe it is now doomed. [1] https://docs.python.org/3/tutorial/controlflow.html#defining-functions -- Ben. -- https://mail.python.org/mailman/listinfo/python-list