Call By Object
“When I use a word, Humpty Dumpty said, in a rather scornful tone, it means just what I choose it to mean, neither more nor less.The question is, said Alice, whether you can make words mean so many different things.
The question is, said Humpty Dumpty, which is to be master — that’s all.”
From time to time, people who’ve read a little CS but not a lot CS (or too much of just one kind of CS) pop up on comp.lang.python and waste a lot of energy trying to tell everyone that Python’s using some calling model that it doesn’t really use. It always turns out that they don’t really understand Python’s model, and quite often, they don’t understand their favourite model either.
But nevermind, the only thing you need to know is that Python’s model is neither “call by value” nor “call by reference” (because any attempt to use those terms for Python requires you to use non-standard definitions of the words “-value” and “-reference”). The most accurate description is CLU’s “call by object” or “call by sharing“. Or, if you prefer, “call by object reference“.
You should also read this, if you haven’t done so already.
The following excerpts are taken from an old comp.lang.python thread. The interesting parts are the CLU texts, which provide a very concise description of Python’s calling model.
(Some day, I’ll turn this into a proper article…)
Date: Wed, 14 May 2003 08:48:08 +0200 > See > > http://wombat.doc.ic.ac.uk/foldoc/foldoc.cgi?call-by-value > > What you describe is call-by-value. It's interesting that you quote FOLDOC, given that FOLDOC doesn't refer to Python's model as call-by-value, as can be seen in the CLU entry: http://wombat.doc.ic.ac.uk/foldoc/foldoc.cgi?CLU "Arguments are passed by call-by-sharing, similar to call-by-value, except that the arguments are objects and can be changed only if they are mutable." Note the use of the words "similar" and "except". For a brief description of CLU's object and argument passing models, see [1]. I think you'll find that it matches Python's model pretty well. The CLU Reference Manual [2] by Liskov et al says (page 14): "We call the argument passing technique _call by sharing_, because the argument objects are shared between the caller and the called routine. This technique does not correspond to most traditional argument passing techniques (it is similar to argument passing in LISP). In particular it is not call by value because mutations of arguments per- formed by the called routine will be visible to the caller. And it is not call by reference because access is not given to the variables of the caller, but merely to certain objects." Note the use of "does not" and the repeated use of "it is not". Let me emphasise: "IN PARTICULAR IT IS NOT CALL BY VALUE because mutations of arguments performed by the called routine will be visible to the caller. And IT IS NOT CALL BY REFERENCE because access is not given to the variables of the caller, but merely to certain objects." CLU was designed in the mid-seventies, and this reference manual was published in 1979. In other literature, the CLU designers some- times refer to this model as "call by object" [3], or they carefully ignore the issue by talking about "objects" instead of values, and "objects that refer to other objects" instead of references [1], but I cannot find a single place where they've gone from "in particular it is not call by value" to "it is call by value". So what's your excuse for being stuck in the early seventies? ;-) </F> 1) http://www.cs.berkeley.edu/~jcondit/pl-prelim/liskov77clu.pdf 2) http://www.lcs.mit.edu/publications/pubs/pdf/MIT-LCS-TR-225.pdf 3) http://www.lcs.mit.edu/publications/pubs/pdf/MIT-LCS-TR-561.pdf
Date: Wed, 14 May 2003 15:49:09 +0200 > Also interesting that [call-by-sharing] is missing did you read the "Why is this definition missing?" page? (the FOLDOC maintainers add links to articles that should be written some day, and keeps track of how many clicks the links get, so they can focus on things that people really want to read about) > For a good intro to semantics, I sugest > > Essentials of Programming Languages > Daniel P. Friedman, Mitchell Wand, Christopher Thomas Haynes if all you have is scheme, etc. > I'm not familiar with CLU I suggest reading reference 3. http://www.lcs.mit.edu/publications/pubs/pdf/MIT-LCS-TR-561.pdf CLU is an important milestone in the development of OO languages; to quote Liskov herself, from the above paper: "The work on CLU, and other related work such as that on Alphard, served to crystallize the idea of a data abstraction and make it precise. As a result, the notion is widely used as an organizing principle in program design and has become a cornerstone of modern programming methodology." if you don't know your history, etc. > but I think this description of Python's argument-passing > semantics is misleading. did you read reference 1? http://www.cs.berkeley.edu/~jcondit/pl-prelim/liskov77clu.pdf in case your PDF reader is broken, here are the relevant portions from that document (any typos etc added by me). "The basic elements of CLU semantics are _objects_ and _variables_. Objects are the data entities that are created and manipulated by CLU programs. Variables are just the names used in a program to refer to objects. In CLU, each object has a particular _type_, which characterizes its behavior. A type defines a set of operations that create and manipulate objects of that type. An object may be created and manipulated only via the operations of its type. An object may _refer_ to objects. For example, a record object refers to the objects that are the components of the record. This notion is one of logical, not physical, containment. In particular, it is possible for two distinct record objects to refer to (or _share_) the same component object. In the case of a cyclic structure, it is even possible for an object to "contain" itself. Thus it is possible to have recursive data structure definitions and shared data objects without explicit reference types. /.../ CLU objects exist independently of procedure activations. Space for objects is allocated from a dynamic storage area /.../ In theory, all objects continue to exist forever. In practice, the space used by an object may be reclaimed when the object isno longer accessible to any CLU program. An object may exhibit time-varying behavior. Such an object, called a _mutable_ object, has a state which may be modified by certain operations without changing the identity of the object. /.../ If a mutable object _m_ is shared by two other objects _x_ and _y_, then a modification to _m_ made via _x_ wil be visible when _m_ is examined via _y_. /.../ Objects that do not exhibit time-varying behavior are called _immutable_ objects, or constants. Examples of constants are integers, booleans, characters, and strings. The value of a constant object can not be modified. For example, new strings may be computed from old ones, but existing strings do not change. Similarily, none of the integer operations modify the integers passed to them as arguments. Variables are names used in CLU programs to _denote_ particular objects at execution time. Unlike variables in many common programming languages, which _are_ objects that _contain_ values, CLU variables are simply names that the programmer uses to refer to objects. As such, it is possible for two variables to denote (or _share_) the same object. CLU variables are much like those in LISP and are similar to pointer variables in other languages. However, CLU variables are _not_ objects; they cannot be denoted by other variables or referred to by objects. /.../ The basic actions in CLU are _assignment_ and _procedure invocation_. The assignment primitive 'x := E' where _x_ is a variable and _E_ is an expression, causes _x_ to denote the object resulting from the evaulation of _E_. For example, if _E_ is a simple variable _y_, then the assignment 'x := y' causes _x_ to denote the object denoted by _y_. The object is _not_ copied, it will be _shared_ by _x_ and _y_. Assignment does not affect the state of any object. (Recall that 'r.s := v' is not a true assignment, but an abbreviation for 'put.s(r, v)'.) Procedure invocation involves passing argument objects from the caller to the called procedure and returning result objects from the procedure to the caller. The formal arguments of a procedure are considered to be local variables of the procedure and are initialized, by assignment, to the objects resulting from the evaluation of the argument expressions. Thus argument objects are shared between the caller and the called procedure. A procedure may modify mutable argument objects (e.g. records), but of course it cannot modify immutable ones (e.g. integers). A procedure has no access to the variables of its caller. Procedure invocations may be used directly as statements; those that return objects may also be used as expressions. Arbitrary recursive procedures are permitted." replace "CLU" with "Python", "record" with "instance", and "procedure" with "function or method", and you get a pretty accurate description of Python's object model. if you don't agree, please tell us what Python does differently. be very specific. </F>
Date: Thu, 15 May 2003 15:55:57 +0200 Tim Peters wrote: > So it goes -- believe it or not, sometimes different people mean different > things by the same words <wink>. that's why you should use URLs and URLs only to identify concepts. > The business of warping "call by value" to mean "the internal address of > the object is the value" doesn't seem common even in the functional world, > though. well, I guess you can, in theory, value an artificial number assigned to an object as much as the object itself. "Joe, I think our son might be lost in the woods" "Don't worry, I have his social security number" </F>
Date: Thu, 15 May 2003 23:11:53 +0200 > No, that's exactly what call-by-value means when applied to Python values > (actually r-values). What happens when you try this: > > >>> y = [1, 2, 3] > >>> x = y > >>> x[:] = [-1]*3 > >>> y > [-1, -1, -1] > > Same behavior, no function calls. except that "x[:] =" *is* a method call. x[:] = [-1]*3 passes a slice object and the result of ([-1]*3) to the x.__setitem__ method, using the standard calling mechanism (that's what the "the object is asked" stuff in the language ref means) "x.y =" is also a method call (__setattr__). so is "x[y] =" (__setitem__, again). however, "x = y" isn't. (and thirty years ago, CLU also had syntactic sugar that looked like assignments for the uninformed observer, but really was yet another way to call a procedure. nothing new here.) </F>
Date: Thu, 15 May 2003 23:39:30 +0200 > According to Joshua, me and R5RS. R5RS says > > "When the procedure is later called with some actual > arguments, the environment in which the lambda expression > was evaluated will be extended by binding the variables > in the formal argument list to fresh locations, the > corresponding actual argument values will be stored > in those locations, and the expressions in the body > of the lambda expression will be evaluated sequentially > in the extended environment." > > That's call-by-value by definition. but that's not how Python works. in Python, the variables in the formal argument list are bound to the actual argument objects. the objects are _shared_ between caller and callee; there are no "fresh locations" or extra "stores" involved. (which, of course, is why the CLU folks called this mechanism "call- by-sharing". and they were real computer scientists, working for a real computer science laboratory ;-) and btw, Python functions doesn't run in an extended environment, either. function bodies have very limited access to the surrounding environment. but that's another story. </F>
Date: Fri, 16 May 2003 00:25:45 +0200 > It's only here that I disagree with you. I consider Python values > themselves to be object references if you keep inventing your own terminology, you'll never win this argument: http://www.python.org/doc/current/ref/objects.html "Objects, values and types" _Objects_ are Python's abstraction for data. All data in a Python program is represented by objects or by relations between objects. Every object has an identity, a type and a value. An object's _identity_ never changes once it has been created; you may think of it as the object's address in memory. /.../ An object's _type_ is also unchangeable. It determines the operations that an object supports (e.g., ``does it have a length?'') and also defines the possible values for objects of that type. /.../ The _value_ of some objects can change. Objects whose value can change are said to be _mutable_; objects whose value is un- changeable once they are created are called _immutable_. (this is basically the same terminology as in the CLU papers, except that they used the term "state" instead of Python's "value") ...so I guess what you've been saying all the time is that Python uses call-by-identity, not call-by-state. fair enough. </F>
Date: Fri, 16 May 2003 01:05:37 +0200 > This is a description of call-by-value using CLU values (object > references). so? if, in doug-speak, object references are the same thing as values, that's also a description of call-by-object-reference. is your point that you can redefine words to make them mean whatever you want? I think we've already noticed that... </F>