Official definition of call-by-value (Re: Finding the instance reference...)

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sat Nov 15 01:51:43 EST 2008


On Fri, 14 Nov 2008 22:56:52 -0500, Terry Reedy wrote:

> rurpy at yahoo.com wrote:
>> On Nov 13, 4:53 pm, Terry Reedy wrote:
>>> rurpy at yahoo.com wrote:
>>>
>>>> I have yet to see any reasonable definition of a Python value in the
>>>> Python docs or elsewhere, despite the fact that a value is one of the
>>>> three defining characteristics of an object, a central concept in
>>>> Python.
>>> I noticed too.  My try:
>>>
>>> The value of an object is the information that the object represents
>>> (or that is stored with the object) that the interpreter uses to
>>> compute the value of a new object when you use the object in an
>>> expression.  For number objects, the number value.  For collection
>>> objects, the objects collected. For functions, the signature and
>>> function performed when called.
>>>
>>> How is that?
>> 
>> I am starting with the idea that "value" is what we call whatever it is
>> that is the difference between, for example, the objects int(3) and
>> int(4).  While your definition seems to be saying something similar it
>> does not seem very precise.
>
> I think necessarily so, or rather, it can only be specific for each
> class.  In the formulation: an object has identify, class, and value,
> class and value are separated.  Others have said that type/class is a
> universe of possible values and operations on those values.  Each
> instance has a particular value. 'Universe of possible values' is vague
> until one gets specific.  For some classes, the possible values are
> rather complex.

I prefer another definition of object: an object *is* a value, rather 
than *has* a value. That value consists of identity, type (or class), and 
everything else of interest which is sometimes also called "value". Since 
identity is usually unimportant, and type is assumed from context, we can 
often get away with stating that the "everything else of interest" is 
*the* value.

I usually talk about one of the three levels of value:

(1) The value of the NAME (or variable) x is the object int(3); that is, 
the thing denoted by the symbol x is the object int(3).


(2) The value of the OBJECT int(3) is the specific concrete instantiation 
that makes it the thing that it is rather than another thing (a 
complicated way of saying that the value of an object is itself); that 
is, the thing denoted by the symbol int(3) is some specific byte pattern 
in memory which causes that object to be int(3) rather than some other 
object.

To put it another way, the value of that object is whatever properties of 
the object distinguish it from any other the whole number 1. Since 
identity is (usually) unimportant for distinguishing one object from 
another (we usually care whether x==y, not whether x is y) the identity 
is not part of the value. We're generally indifferent to the serial 
number on our ten dollar bills: any note is (usually) as good as any 
other note. But sometimes identity is important, and in some specific 
contexts I'd be happy to say that the value of a symbol must include the 
identity of the object.


(3) But at another level, the value of the object int(3) is the abstract 
integer three. This is the only level at which I'm happy to talk about 
objects (as opposed to names) "having" a value: "object int(3) has the 
value three".


 
>> How would I use your definition to answer the following questions?
>> 
>> * How does an object get a value?
> 
> A Python interpreter, human or electronic, creates objects with values
> as directed by Python code.  How it does so is its private secret ;-).
> The directive code includes literals, expressions, and some statements.

I would answer that the object *is* the value, but with the proviso that 
we usually don't care about identity:

>>> x = 19990
>>> y = 19990
>>> x == y
True
>>> x is y
False

I'm happy to say that the value of x and the value of y are the same, 
even though they have different identities. But context is important: 
there are times were I would want to wrap identity under the umbrella of 
value. See below.

 
>> * Can I create an object that has a value that
>>  is the same as int(3) without somehow using an int(3) object in its
>>  construction?
> 
> Yes: 1 + 2
> Yes: mpz(3) where mpz is multi-precision int class with same set of
> possible values as Python ints.
> 
> ??? 3.0
> ??? Fraction(3,1)
> 
> While Python sees these as *equal*, one could say they are not the same
> because they indicate members of different (non-isomorphic) universes.

Whether we wish to say that mpz(3) has the same value as int(3) depends 
on what we care about, and we only care about that because our data types 
are leaky abstractions. In principle, we should be indifferent to whether 
x is int(3), float(3.0), mpz(3), or any other instantiation of the 
abstract numeral three. In practice, we're not indifferent: we prefer 
ints for mpz objects for some purposes, but not for others. If we care 
about the specifics, then we might say they have different values 
(because they have different types, and therefore different 
characteristics). If we care only about the thing they represent, the 
abstract number three, then we'd say that they have the same value.


 
>> * Do all objects have values? (Ignore the Python
>>  docs if necessary.)
> 
> If one allows null values, I am current thinking yes. Still, numbers,
> characters, and collections thereof of what code is usually about.

I would say that all objects *are* values, rather than *have* values. The 
value of None is the object None, which is a concrete instantiation of a 
selected subset of behaviour of the null object pattern.


 
>> * What is the value of object()?
> 
> Essentially none, other than bool(object()) == True. Ditto for None,
> other than bool(None) == False. Otherwise, None and object convey no
> information.

I would say that the "everything of interest" I referred to above is the 
empty set: object() has little or no state. But of course having no state 
is itself a state, in the same way that 0 is a perfectly good integer.

In practice, I'd say that object() is one of those cases where we should 
include identity in the value. Although we're indifferent as to *which* 
object() instance we get, once we've got one, we care whether other 
instances are the same instance or different ones. Imagine that object() 
keeps a cache of instances, and returns one instead of creating a brand 
new object. We don't care which instance we get, or even whether it comes 
from the cache or is created fresh. But once we have one, we care about 
the identities of others:

special = object()  # we don't care which object instance we get
if special is some_other_instance():
    print "Match!"



>> * Does an object's behavior (methods) affect
>>  its value?
> 
> My first answer is No.  Instance methods are attributes of a class and,
> in most cases, the value of a class.  In those cases in which the class
> of an object can be and is changed to another class, the interpretation
> of the value/info of the instance could change and one might claim that
> the effective value and hence the value of the object has changed and
> hence the answer could be Yes.  But this is extremely rarely done and I
> could claim that this is a shortcut for creating a new object and
> deleting the old.

I would say that the answer to this is, "Would you like to include 
behaviour in value?". Let me give you an example:

class String(string):
    def upper(self):
        return "spam"

s1 = "Norwegian Blue"
s2 = String("Norwegian Blue")


Do s1 and s2 have the same value? 

Using definition (1) above, we can see that the names s1 and s2 refer to 
different objects, so the names have different values.

Using definition (2), the objects s1 and s2 have different concrete 
expressions, and so they are different values. (Remember: the object is 
the value.) But from definition (3) they both represent that same 
abstract string, so if I care only about that level of description, I'd 
say yes they *have* the same value but *are* different values.

Assuming I cared about the behaviour of upper(), then s2 is probably not 
suitable for my purposes and so I would like to distinguish s1 from s2. 
I'd insist that they have different values which merely looked the same 
under equality. To use the bank note analogy, then s1 is legal tender but 
s2 is just a very good forgery.

But note that to a collector of forgeries, s2 might be more valuable than 
s1, and presumably the writer of class String had a reason for the 
behaviour given. The answer to the question "do s1 and s2 have different 
values" will depend on why you are asking.


 
[snip]
>> Or perhaps value is some sort of useful but fundamentally undefinable
>> concept
> 
> Either yes or defined in terms of information or universes.
> 
>> that disappears when looked at too closely
> 
> No.

I would say that although value is dependent on context, that's no excuse 
for concluding that it has no meaning. If you look too closely at 
*anything*, it becomes fuzzy. (Well, with the possible exception of pure 
mathematics.)



-- 
Steven



More information about the Python-list mailing list