Finding the instance reference of an object

D

Douglas Alan

greg said:
Seems to me that (1) describes exactly how parameter passing
works in Python. So why insist that it's *not* call by value?

Because there's an important distinction to be made, and the
distinction has been written up in the Computer Science literature
since Lisp first starting using the same argument passing semantics as
Python back in 1958. The semantics are called "call by sharing".

Many mainstream programming languages other than Python now use call
by sharing. They include Java, JavaScript, Ruby, ActionScript, and C#.

|>oug

P.S. Lisp didn't call it "call by sharing" -- Lisp called it
"binding". The designers of CLU invented the term "call by sharing"
back in the 70s. (Or at least I believe they invented the term. They
certainly did use the term.)
 
G

Gabriel Genellina

Whether it behaves like C is not the test.

Let's look at the definitions of the terms:

(1) Call by value: The actual parameter is an expression. It is
evaluated and the result is assigned to the formal parameter.
Subsequent assignments to the formal parameter do not affect
the actual parameter.

(2) Call by reference: The actual parameter is an lvalue. The
formal parameter becomes an alias for the actual parameter,
so that assigning to the formal parameter has the same
effect as assigning to the actual parameter.

Seems to me that (1) describes exactly how parameter passing
works in Python. So why insist that it's *not* call by value?

Those definitions are only applicable to unstructured, primitive types,
where the only relevant operations are "get value" and "assign value".
Structured types provide other operations too - like selection (attribute
get/set in Python). It is unspecified on both definitions above what
happens in those cases. Other posts in this same thread showed that Python
behaves similarly to call-by-reference in C++ with regard to data members
inside a structure (that is, mutable objects *can* be changed, and the
caller sees the change). Combined with your previous conclusion that
Python implements call-by-value, one should finally conclude that it can't
be neither cbv nor cbr - it's a different thing.
The term "call by object" was coined in the late '70s to describe this
behavior. More info about this ever-recurring topic can be found at
http://effbot.org/zone/call-by-object.htm
 
G

Gabriel Genellina

So, then, what to tell a C++ programmer about how Python passes
arguments? You say: tell them Python only passes by value. I disagree,
because I think that would confuse them. Rather than try to map C++
conventions onto Python, I think it is more useful to just tell them how
it really works. Maybe a few statements like this:

All values in Python are objects, from simple integers up to complex
user-defined classes.

An assignment in Python binds a variable name to an object. The
internal "value" of the variable is the memory address of an object,
and can be seen with id(var), but is rarely needed in practice.

The "value" that gets passed in a Python function call is the address
of an object (the id()).

When making a function call, myfunc(var), the value of id(var) can
never be changed by the function.

Not sure if these are the best. To get into much more detail, you have
to start explaining mutable and immutable objects and such.

I don't think the above explanation is desirable, nor needed. Objects in
Python don't have an "address" - it's just a CPython implementation
detail. The fact that id() returns that address is just an implementation
detail too. The calling mechanism should be explained without refering to
those irrelevant details.
 
J

Joe Strout

En Tue, 28 Oct 2008 00:58:10 -0200, greg

Greg is right on the money here. It really is as simple as that.
Those definitions are only applicable to unstructured, primitive
types, where the only relevant operations are "get value" and
"assign value".

Nonsense. They apply to any type. See here for an introduction to
the topic in VB.NET:

http://www.homeandlearn.co.uk/net/nets9p4.html

The example shown uses an Integer, but guess what -- you can pass ANY
type either ByRef or ByVal, including object references (which are, of
course, quite common in VB.NET). The default is ByVal, which means
that (as in Python) the actual parameter is an expression, and no
assignments to it can affect the actual parameter. It DOES NOT MATTER
that both the formal parameter and the actual parameter may refer to
the same object, and if that object is mutable, you can mutate that
object.

But ByRef is another option, and if you pass an object reference
ByRef, then the formal parameter is an alias for the actual parameter,
and assignments to it change the actual parameter. Python doesn't
have this feature (nor much need for it, given its other features,
like tuple packing/unpacking). So, parameter passing in ByRef is
clearly exactly the same as the default "ByVal" parameter passing in
VB.NET... as well as Java, RB, C++ (when you remember that an object
reference in modern languages is like a pointer in C++), and every
other OOP language I've looked into.

Some of those languages, like Python, don't have different modes, and
so the language designers had no call to give their one mode a name.
So let's look at those that did have such a need, like VB.NET and
REALbasic. What's the default mode called? Why, it's "ByVal". Even
when that value is an object reference. This is short for "by value"
-- it's not short for "by sharing" or "by object" or any other such
silliness. No such terms are needed.

There are only the two cases, which Greg quite succinctly and
accurately described above. One is by value, the other is by
reference. Python quite clearly uses by value. Parameters are
expressions that are evaluated, and the resulting value copied into
the formal parameter, pure and simple. The continued attempts to
obfuscate this is pointless and wrong.

Best,
- Joe
 
D

Dale Roberts

En Tue, 28 Oct 2008 01:16:04 -0200, Dale Roberts <[email protected]>  
escribió:









I don't think the above explanation is desirable, nor needed. Objects in  
Python don't have an "address" - it's just a CPython implementation  
detail. The fact that id() returns that address is just an implementation  
detail too. The calling mechanism should be explained without refering to  
those irrelevant details.


I agree that it was a feeble and ill-advised attempt, and would like
to strike those lines from the record...

But the rest of the post is strong and accurate, I think, and coming
from a mainly C/C++ background, visualizing these object references
being passed around does help improve my understanding of Python's
*behavior* (and it apparently helps Joe too).

[May I refer to you as "Joe The Programmer" in my rhetoric? Are you a
"licensed" programmer making over $250K/year? ;-)]

If asked by a C++ programmer about Python's argument passing, I will
go with the Pass By Object explanation (which is why I called my
Python routine above ByObject()). Although there will be more
'splaining to do, at least it will give the C++ programmer pause, and
help them realize that there is something a little different that they
need to stop and try to understand.

If I just say "Python is Pass By Value, Period" without further
explanation, they will expect things to work as in my ByValue()
example above (where the caller's object contents cannot be changed),
and that is incorrect. And they may go and tell someone else, without
the detailed explanation, that "Dale says it's Pass By Value", and
I'll get blamed when their function surprisingly changes the contents
of the caller's object.

If I just say "Python is Pass By Reference", that is wrong too. As Joe
The Programmer points out, they will expect that the calling
*variable* itself can be changed, and that is wrong too.

They need to understand that Python does not map neatly, directly, and
completely to their C++ experience of Pass By Value (which involves
copying a variable), or Pass By Reference (which involves taking the
address of a variable).

The Key Concept in for a C++ programmer looking at Python is that,
unlike in C++, **Variables Cannot "Contain" Values**. All values in
Python are objects, and all variables in Python simply point to, or
are bound to, or refer to, these objects. The variables themselves do
not contain the objects - if you must (like Joe the Programmer), you
can say that all Python variables *contain* an object reference, and
it is these references that are passed around. Unlike C++, an object
reference is the ONLY thing that a Python variable can contain. A
function parameter is always passed as a reference to an object, not a
reference to a variable, or a copy of a variable or object.

And that is where the confusion arises. When people say ByRef or
ByVal, they usually mean by Reference to (address) or Value of (copy)
the *contents* of the passed variable. But, PYTHON VARIABLES DO NOT
"CONTAIN" VALUES (sorry for the shouting, but it is the most important
point here), so ByRef and ByVal lose their commonly accepted meanings.

In C++, ByValue requires a copy (and Python does not copy). In C++,
ByReference requires the address of a *variable* (an "lvalue"), and
variables do not have accessible addresses in Python.

ByObject, in contrast, requires neither (unless, like Joe The
Programmer, you consider the "value" of a variable to be the id(),
which is not what most people expect when they say "x=5" - they expect
the "value" to be 5). ByObject simply passes an object reference. Nice
and neat.

I think with that explanation (avoiding any mention of memory, or
object id's) will help them understand things better.

As you point out, this is a very old topic, but I guess each newcomer
to Python has to figure it out. The effbot's article you mention are
very helpful, and much of this thread is just a rehash of what he has
long ago spelled out very clearly.

But I am happy to add the strong C++ slant, since that is what I
understand best.

I like either "Call By Object", or "Call By Object Reference", the
latter of which is what Joe The Programmer seems to like, but insists,
confusingly, on rebinding it to the name "call by value".

dale
 
D

Dale Roberts

...

There are only the two cases, which Greg quite succinctly and  
accurately described above.  One is by value, the other is by  
reference.  Python quite clearly uses by value.  Parameters are  
expressions that are evaluated, and the resulting value copied into  
the formal parameter, pure and simple.  The continued attempts to  
obfuscate this is pointless and wrong.

Best,
- Joe

5 + 3

What is the "value" of that expression in Python? Can you tell me?

99.99% of programmers (who do not have this thread as context) will
say that the value is 8. But you say the value is the memory address
of the resulting object created when the + operator is applied to the
5 object and the 3 object. That is the "value" that is copied.

Okay, you can have it that way, but every time you explain to someone
that Python passes "By Value", you will have to add the additional
baggage that, oh, by the way, there is a completely different meaning
for "value" in Python than what you are used to.

Then the questions and puzzled looks will start...

And when they tell their friend that Joe The Programmer said it's Pass
By Value, your additional context may not be present any longer, and
the friend will be very confused.

In my opinion, best just to head it off and call it something
different so as not to confuse.

dale
 
A

Aaron Brady

That's correct, but of course, C is a decades-old language barely a  
step above assembler.  For a fair comparison, pick any modern OOP  
language, including the C derivatives (C++, Objective-C, Java), and  
compare a Python object to an object in that language, rather than to  
a struct.


Exactly!  In C++, this would be like a pointer variable.  In Java, RB,  
or .NET, it's like an object reference.


Agreed.  (And this was my point in response to someone arguing that no  
such location exists.)


Right.  The variables contain object references; these object  
references are copied (not referenced!) when you pass them into a  
function.  That's call by value.

snip.

What do you propose the name of the method of passing parameters
should be for the following function 'f' in C?

struct T {
int a;
int b;
int c;
};

void f( T t );

Given a 4-byte system word, how many bytes do you think are copied to
the stack upon calling 'f'?
 
S

Steven D'Aprano

There are only the two cases, which Greg quite succinctly and accurately
described above. One is by value, the other is by reference. Python
quite clearly uses by value.

That is absolute nonsense, based on the idiotic assumption that
programmers should care more about an arbitrary reference to a value than
to the value itself.

I'm sure I've quoted the excellent effbot before, but he deserves
repeating:

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"
[end quote]

As I wrote yesterday:

The value of a Python name is the Python object assigned to it, not an
arbitrary memory location that points to the object. Even you would
consider it obfuscatory if I executed this code:

x = "Norwegian Blue"

and then insisted that the value of x was "3086179808L, but if I run that
line of code again it could get another value, and naturally if you run
it on your computer you're almost certain to get a different value".

By your definition of "value=reference", the above is perfectly correct,
and utterly, completely pointless, useless and unhelpful. It's rather
like listing the ingredients of a cake as "Atoms". Technically true, but
missing the point.

Once we discard the unhelpful assumption that value=reference, your
entire argument falls apart.
 
D

Douglas Alan

Joe Strout said:
There are only the two cases, which Greg quite succinctly and
accurately described above. One is by value, the other is by
reference. Python quite clearly uses by value.

You make a grave error in asserting that there are only two cases.
Algol, for instance, used call-by-name, which is neither call-by-value
or call-by-reference. There are a number of other evaluation
strategies. For a primer on the subject see the following Wikipedia
page:

http://en.wikipedia.org/wiki/Evaluation_strategy

CLU used the termed "call-by-sharing" for the evaluation strategy
shared by Python, Lisp, CLU, Java, Ruby, and JavaScript, etc.

It should be noted that the Wikipedia page does not document
"call-by-sharing", in specific and refers to Python's strategy as a
type of call-by-value. It also notes that call-by-value is not a
single evaluation strategy, but rather a family of evaluation
strategies, and that the version of the strategy used by Java (and
hence Python) shares features with call-by-reference strategies.

Consequently, many people prefer to use a different name from
"call-by-value" for Python/Java/Lisp's strategy in order to avoid
confusion. In any case, no one can disagree with the fact that the
evaluation strategy used by Python et. al., differs significantly from
the call-by-value evaluation strategy used by C and the like, whatever
you wish to call it.

|>oug
 
A

Antoon Pardon

They are, though. The only difference you've pointed out is that
*numbers* are different in Python vs. C, and that's an internal
implementation detail I was blissfully unaware of until this
discussion. (I'm grateful to know it, but it really doesn't matter in
day-to-day coding.)

No they are not. An assignment in Python is like making an (new) alias/reference,
while an asignment in C is copying the content of one variable into another.
 
D

Dale Roberts

...

There are only the two cases, which Greg quite succinctly and  
accurately described above.  One is by value, the other is by  
reference.  Python quite clearly uses by value.  Parameters are  
expressions that are evaluated, and the resulting value copied into  
the formal parameter, pure and simple.  The continued attempts to  
obfuscate this is pointless and wrong.

Best,
- Joe

Joe, you are being too generous and expansive here.

[Play along with me for a minute here...]

Don't you know? There is really only *ONE* case, and, you are right,
it is Pass By Value. There is no such thing as Pass By Reference at
the physical CPU level at all, right? If there is, show it to me. Pass
By Reference is just a silly idiom developed by high-minded CS
academics to confuse the rest of us. It has no practical use and
should not be given its own name, when we already have a good an
proper name for it.

Let me demonstrate with 3 examples of a function definition, and the
appropriate calling syntax for that function in C++, all sharing the
common "int i" global variable:

int i = 5;

myfunc(int &val){} /*CALL:*/ myfunc(i); // "ByRef" (ya, right!)
myfunc(int val){} /*CALL:*/ myfunc(i); // ByVal
myfunc(int *val){} /*CALL:*/ myfunc(&i); // Joe's ByVal

The first is what all the fakers call "Pass By Reference" - sheesh,
how naive. We all know that what *really* happens internally is that
the *address* of val (A VALUE itself, or course) is copied and passed
on the stack, right? There couldn't be a more straightforward example
of Pass By Value (unless it's an inline function, or optimized away,
or possibly when implemented in a VM, or...). It passes the *address*
of i by value, then we can access the *value* of i too via
indirection. Hmm, did we need to have two definitions of VALUE there?
Well, never mind, no one will notice...

The next is obviously pass by value. It's right out there. The value
of i (which is what we are talking about, right?) is copied out, and
passed right on the stack in plain daylight where we can all see it.

How about the third? Pass By Value, obviously, of course. This is the
version you are defending, right? The parameter's value, &i, is
evaluated and copied right onto the stack, just like in the first
example. In fact, if you compare the assembler output of the first and
third examples, you may not even see a difference. Never mind the
actual contents of that pesky "i" variable that most people are
referring to when they use the term "value". We don't need to dress up
example 3 and call it an "idiom" where we are really passing a so-
called "reference" of the variable "i". Indeed! Don't insult our
intelligence. We can all see that it's an address passed by value,
plain and simple.


Pass By Reference? So "postmodern". Who needs it. Show me a so-called
"reference". I've looked at the assembler output and have never seen
one. There is no such thing.

"The continued attempts to obfuscate this is pointless and wrong."


---------------
I hate to have to add this, but for those not paying close attention:

;-)

dale

(tongue back out of cheek now)
 
C

Chuckk Hubbard

Don't you know? There is really only *ONE* case, and, you are right,
it is Pass By Value. There is no such thing as Pass By Reference at
the physical CPU level at all, right? If there is, show it to me. Pass
By Reference is just a silly idiom developed by high-minded CS
academics to confuse the rest of us. It has no practical use and
should not be given its own name, when we already have a good an
proper name for it.

Let me demonstrate with 3 examples of a function definition, and the
appropriate calling syntax for that function in C++, all sharing the
common "int i" global variable:

int i = 5;

myfunc(int &val){} /*CALL:*/ myfunc(i); // "ByRef" (ya, right!)
myfunc(int val){} /*CALL:*/ myfunc(i); // ByVal
myfunc(int *val){} /*CALL:*/ myfunc(&i); // Joe's ByVal

The first is what all the fakers call "Pass By Reference" - sheesh,
how naive. We all know that what *really* happens internally is that
the *address* of val (A VALUE itself, or course) is copied and passed
on the stack, right? There couldn't be a more straightforward example
of Pass By Value (unless it's an inline function, or optimized away,
or possibly when implemented in a VM, or...). It passes the *address*
of i by value, then we can access the *value* of i too via
indirection. Hmm, did we need to have two definitions of VALUE there?
Well, never mind, no one will notice...

The next is obviously pass by value. It's right out there. The value
of i (which is what we are talking about, right?) is copied out, and
passed right on the stack in plain daylight where we can all see it.

How about the third? Pass By Value, obviously, of course. This is the
version you are defending, right? The parameter's value, &i, is
evaluated and copied right onto the stack, just like in the first
example. In fact, if you compare the assembler output of the first and
third examples, you may not even see a difference. Never mind the
actual contents of that pesky "i" variable that most people are
referring to when they use the term "value". We don't need to dress up
example 3 and call it an "idiom" where we are really passing a so-
called "reference" of the variable "i". Indeed! Don't insult our
intelligence. We can all see that it's an address passed by value,
plain and simple.


Pass By Reference? So "postmodern". Who needs it. Show me a so-called
"reference". I've looked at the assembler output and have never seen
one. There is no such thing.

You are so right! We also don't need "object-oriented programming".
I looked at the motherboard and I don't see any objects moving around!
I don't see any values being passed, either.
When I turn on the TV and see Chuck Norris, though, I know it's only a
reference to Chuck Norris, or I would be blinded. The only case he
needs is "Pass By Roundhouse Kick".

-Chuckk
 
F

Fuzzyman

Greg is right on the money here.  It really is as simple as that.


Nonsense.  They apply to any type.  See here for an introduction to  
the topic in VB.NET:

   http://www.homeandlearn.co.uk/net/nets9p4.html

The example shown uses an Integer, but guess what -- you can pass ANY  
type either ByRef or ByVal, including object references (which are, of  
course, quite common in VB.NET).  The default is ByVal, which means  
that (as in Python) the actual parameter is an expression, and no  
assignments to it can affect the actual parameter.  It DOES NOT MATTER  
that both the formal parameter and the actual parameter may refer to  
the same object, and if that object is mutable, you can mutate that  
object.

You're pretty straightforwardly wrong. In Python the 'value' of a
variable is not the reference itself. If that sentence has any meaning
for Python then the value is the object itself.

..NET does draw a distinction between 'value types' and reference types
- where using reference types are called by reference (the reference
is passed) and value types are called by value (the value itself is
copied).

Value types (all numeric types, structs, enumerations etc) actually
live on the stack, whereas reference types (strings, classes etc) live
in the heap and have a
pointer on the stack.

It is complicated by the fact that .NET perpetuates the myth that the
primitives (the value types) inherit from System.Object (a reference
type). The runtime does auto-boxing for you where this matters.

This means that when you pass a value type into a method the value
*is* copied. Structs can be arbitrarily big, so this can be a
performance problem. It is often a performance win for working with
the numeric types as you remove a level of indirection.

It isn't without problems though - and some of these can be seen in
IronPython.

System.Drawing.Point is a struct, but it is effectively a mutable
value type. However, when you access it you are often accessing a copy
- and if you attempt to mutate it then your changes will be lost.

The following code illustrates the problem:

0

Because r.Location returns a value type (a Point), the update to it is
'lost'.

By this definition Python objects (all of them) are clearly reference
ypes and not value types.

In .NET you can specify that a parameter to a method takes a reference
('out' in C# or ByRef in VB.NET). If you pass in a value type as a
reference parameter then the .NET runtime will do boxing / unboxing
for you.

This means that we can write code like the following C#:

int x = 3;
SomeMethod(out x);

The value of x can be changed by 'SomeMethod' and can have a different
value - something that can't happen in Python.

In a 'way' immutable Python types behave a bit like .NET value types,
and mutable types like reference types. As you can see, this analogy
breaks down.

Michael Foord
 
S

Steven D'Aprano

...

There are only the two cases, which Greg quite succinctly and
accurately described above.  One is by value, the other is by
reference.  Python quite clearly uses by value.  Parameters are
expressions that are evaluated, and the resulting value copied into the
formal parameter, pure and simple.  The continued attempts to obfuscate
this is pointless and wrong.

Best,
- Joe

Joe, you are being too generous and expansive here.

[Play along with me for a minute here...]

Don't you know? There is really only *ONE* case, and, you are right, it
is Pass By Value. There is no such thing as Pass By Reference at the
physical CPU level at all, right? If there is, show it to me. Pass By
Reference is just a silly idiom developed by high-minded CS academics to
confuse the rest of us. It has no practical use and should not be given
its own name, when we already have a good an proper name for it.
[snip]

But Dale, you're wrong. At the physical CPU level, there's no copying of
bits at all. If we could copy bits, then we could start with 512MB of RAM
and say "copy all the bits" and end up with 1GB of RAM. So-called copying
is actually just bit-flipping.

So anyone who talks about copying parameters is talking nonsense. There
is no "pass by value". It's all pass by bit-flipping.
 
J

Joe Strout

You're pretty straightforwardly wrong. In Python the 'value' of a
variable is not the reference itself.

That's the misconception that is leading some folks around here into
tangled nots of twisty mislogic, ultimately causing them to make up
new terms for what every other modern language is perfectly happy
calling Call-By-Value.

I've thought a lot about why this misconception is so widespread here,
and I think it must be one of the following:

1. There was one community leader with this idea, who has been
successful at promoting it widely, much to the detriment of all; or,

2. Because everything in Python is an object, you're not forced to
think clearly (and more generally) about references as values as you
are in languages (such as Java, VB.NET, etc.) which have both simple
types and object types.

Either way, it's wrong (or at least, a needlessly complicated way of
looking at things).
.NET does draw a distinction between 'value types' and reference types
- where using reference types are called by reference (the reference
is passed) and value types are called by value (the value itself is
copied).

Quite right. Now, note that "ByRef" and "ByVal" apply to both.
Generalize to Python. There you go.

Best,
- Joe

P.S. I really am trying to quit responding to this thread. Sometimes
the urge is too strong. But I'll keep trying!
 
S

Steve Holden

Joe said:
That's the misconception that is leading some folks around here into
tangled nots of twisty mislogic, ultimately causing them to make up new
terms for what every other modern language is perfectly happy calling
Call-By-Value.
I tried hard to make myself believe that the above was a clever pun and
knot [sic] a typo. Sadly I failed.
I've thought a lot about why this misconception is so widespread here,
and I think it must be one of the following:

1. There was one community leader with this idea, who has been
successful at promoting it widely, much to the detriment of all; or,

2. Because everything in Python is an object, you're not forced to think
clearly (and more generally) about references as values as you are in
languages (such as Java, VB.NET, etc.) which have both simple types and
object types.
How about

3. You just hate being wrong.
Either way, it's wrong (or at least, a needlessly complicated way of
looking at things).
One that has apparently served for almost twenty years now.
Quite right. Now, note that "ByRef" and "ByVal" apply to both.
Generalize to Python. There you go.

Best,
- Joe

P.S. I really am trying to quit responding to this thread. Sometimes
the urge is too strong. But I'll keep trying!
We must tax your patience dreadfully. I have suffered from the same
myself, but I fear we are doomed to pursue each other until Godwin's law
releases us.

Which reminds me, had you thought about submitting a paper along these
lines to PyCon? If we meet at PyCon at least let me buy you a pint to
show there are no hard feelings.

regards
Steve
 
F

Fuzzyman

That's the misconception that is leading some folks around here into
tangled nots of twisty mislogic, ultimately causing them to make up
new terms for what every other modern language is perfectly happy
calling Call-By-Value.

I've thought a lot about why this misconception is so widespread here,
and I think it must be one of the following:

1. There was one community leader with this idea, who has been
successful at promoting it widely, much to the detriment of all; or,

2. Because everything in Python is an object, you're not forced to
think clearly (and more generally) about references as values as you
are in languages (such as Java, VB.NET, etc.) which have both simple
types and object types.


But those languages clearly make the distinction between values and
references that you refuse to make! Go figure...

Michael
 
F

Fuzzyman

That's the misconception that is leading some folks around here into
tangled nots of twisty mislogic, ultimately causing them to make up
new terms for what every other modern language is perfectly happy
calling Call-By-Value.

I've thought a lot about why this misconception is so widespread here,
and I think it must be one of the following:

1. There was one community leader with this idea, who has been
successful at promoting it widely, much to the detriment of all; or,

2. Because everything in Python is an object, you're not forced to
think clearly (and more generally) about references as values as you
are in languages (such as Java, VB.NET, etc.) which have both simple
types and object types.


To make it clearer for you, call by value means that the value is
copied in - and therefore changes to the value won't be visible to the
caller.

In .NET this is true of mutable value types - changes made are made to
a copy and not visible to the caller. In Python we *only* have
reference types, so changes to *any* mutable object are visible to the
caller.

In .NET you can call by reference with a value type - and the runtime
does boxing for you so that you can see the changes. You have to
explicitly ask for call by reference though.

Michael
 
D

Dale Roberts

That's the misconception that is leading some folks around here into  
tangled nots of twisty mislogic, ultimately causing them to make up  
new terms for what every other modern language is perfectly happy  
calling Call-By-Value.

Doesn't this logic also apply to Call By Reference? Isn't that term
redundant too? (see my 3 C++ examples above). If not, why not? Are you
saying that C++ is capable of using the Call By Reference idiom, but C
is not, because C does not have a reference designation for formal
function parameters?

"Call By Object Reference" is an idiom, just like Call By Reference.
It is not a physical description of what is going on internally at the
register/stack level (which is always just shuffling values around -
or flipping bits, as Steven points out), it is a higher level concept
that helps people understand the *intention* (not necessarily the
implementation) of the mechanism.

You cannot look a C++ programmer straight in the eye and say that
"Python uses Call By Value, Period", without also informing them that
"Python variables can ONLY EVER hold object references - that is the
only "value" they can ever hold". Then the C++ programmer will go "Oh,
yea, that makes sense".

Instead of having to say all of that, we just give it a new name.
Instead of "Call By Value, Where Every Single Value Is Only Ever A
Reference To An Object Which Contains The Actual Value That
Programmers Usually Refer To", we just say "Call By Object Reference".
...
2. Because everything in Python is an object, you're not forced to  
think clearly (and more generally) about references as values

I think we've shown that we are all in fact thinking clearly about it,
and we all (you included, of course!) understand what is going on.
It's just a matter of what words we choose to describe it.

Using your definition of value, though, I believe that if you want to
throw out Call By Object Reference, you also have to throw out Call By
Reference. See my 3 C++ examples above. And just for fun I did look at
the assembler output, and, indeed, the output for examples 1 and 3 is
absolutely identical. They are the same thing, as far as the CPU is
concerned.

Would you give them different names?

dale
 
J

Joe Strout

Doesn't this logic also apply to Call By Reference? Isn't that term
redundant too? (see my 3 C++ examples above). If not, why not?

It's not. Wikipedia explains the difference pretty well.
Are you saying that C++ is capable of using the Call By Reference
idiom,
but C is not, because C does not have a reference designation for
formal
function parameters?

It's been a LONG time since I did anything in C, but yes, I believe
that reference parameters were an addition that came with C++.
"Call By Object Reference" is an idiom, just like Call By Reference.
It is not a physical description of what is going on internally at the
register/stack level (which is always just shuffling values around -
or flipping bits, as Steven points out), it is a higher level concept
that helps people understand the *intention* (not necessarily the
implementation) of the mechanism.

Right. And you can easily tell the difference, by whether an
assignment to the formal parameter causes any change to the actual
parameter that was passed in. If it does, that's call-by-reference.
If it doesn't, it's call-by-value. In Python, it doesn't. In VB.NET
(and relatives), it doesn't if the parameter is declared (explicitly
or implicitly) "ByVal", and does if it's declared "ByRef". (Whether
the parameter is a reference type or a simple value type makes no
difference.)

Python's behavior is exactly and always equivalent to the "ByVal"
behavior of languages that have both behaviors. It also matches the
definition of call-by-value. I quite agree that it's not helpful to
delve into the physical flipping of transistor states. We're talking
about the behavior, and the behavior, very clearly, is call-by-value.
To call it something else only clouds the issue and results in
confusion. (Perhaps explaining why there appears to be far more
confusion about call semantics in the Python community than in the
community of other languages where the default semantics are exactly
the same.)

Best,
- Joe
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,128
Latest member
ElwoodPhil
Top