anything like C++ references?

8 views
Skip to first unread message

Tom Plunket

unread,
Jul 12, 2003, 4:53:35 PM7/12/03
to
I want to do something along the lines of the following C++ code:

void change(int& i)
{
i++;
}


Is there any way to do references like this in Python? It'd be
like this, though clearly this doesn't change the thing I want it
to change:

def change(val):
val += 1

v = 0
change(v)

# v == 1 now.

thanks.

I can see that maybe if I passed in a list of one integer I could
change that, but that seems circuitous to me.


-tom!

"Martin v. Löwis"

unread,
Jul 12, 2003, 5:12:16 PM7/12/03
to Tom Plunket
Tom Plunket wrote:

> Is there any way to do references like this in Python?

No.

Martin

Ian Bicking

unread,
Jul 12, 2003, 6:56:57 PM7/12/03
to
On Sat, 2003-07-12 at 17:45, Brian Quinlan wrote:
> > void change(int& i)
> > {
> > i++;
> > }
>
> The idiomatic way to write this code in python would be:
>
> def change(val):
> return val + 1

To be more specific, you would achieve the same effect with:

def change(val):
return val + 1
i = change(i)

As opposed to the C++ where you'd do:

change(i) // no assignment needed


There is no direct Python equivalent to the C++ function, for all sorts
of reasons (most of them very deliberate).

Is there someplace in particular to reference people who need to learn
about what Python variables are (that they are bindings, etc)? This
question comes up in many forms all the time, particularly from people
with a C background. Or rather, there are many questions all of which
are answered by that explanation (so we can't expect people to stop
asking, but maybe we can make the answers easier and clearer). Or maybe
a general Python-for-C-programmers tutorial...

Ian

Brian Quinlan

unread,
Jul 12, 2003, 6:45:03 PM7/12/03
to
> void change(int& i)
> {
> i++;
> }

The idiomatic way to write this code in python would be:

def change(val):
return val + 1

If you don't want to write it this way for some reason, you will have to
explain why.

Cheers,
Brian


Erik Max Francis

unread,
Jul 12, 2003, 7:09:16 PM7/12/03
to
Tom Plunket wrote:

> Is there any way to do references like this in Python? It'd be
> like this, though clearly this doesn't change the thing I want it
> to change:

Hi, Tom.

There's no builtin support for this in Python, but you can do it
yourself easily enough. Pass in a mutable container, and then twiddle
the object you want inside it.

>>> def change(val):
... val[0] += 1
...
>>> v = [0]
>>> change(v)
>>> v
[1]

I'm a strong believer in writing self-documenting code, so in a case
like this I write a (trivial) class that makes my intent crystal clear:

>>> class Container:
... def __init__(self, value=None): self.value = value
... def get(self): return self.value
...
>>> class Container:
... def __init__(self, value=None): self.value = value
... def get(self): return self.value
... def set(self, value): self.value = value
...
>>> def change(container):
... container.set(container.get() + 1)
...
>>>
>>> c = Container(0)
>>> change(c)
>>> c.get()
1

--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
__ San Jose, CA, USA && 37 20 N 121 53 W && &tSftDotIotE
/ \ Winners are men who have dedicated their whole lives to winning.
\__/ Woody Hayes

Dave Brueck

unread,
Jul 12, 2003, 10:15:36 PM7/12/03
to
On Saturday 12 July 2003 04:56 pm, Ian Bicking wrote:
> On Sat, 2003-07-12 at 17:45, Brian Quinlan wrote:
> > > void change(int& i)
> > > {
> > > i++;
> > > }
> >
> > The idiomatic way to write this code in python would be:
> >
> > def change(val):
> > return val + 1
>
> To be more specific, you would achieve the same effect with:
>
> def change(val):
> return val + 1
> i = change(i)
>
> As opposed to the C++ where you'd do:
>
> change(i) // no assignment needed
>
>
> There is no direct Python equivalent to the C++ function, for all sorts
> of reasons (most of them very deliberate).

Your response above (that the normal thing to do in Python is just return the
modified value) made me wonder if most people are asking about
pass-by-reference not because they want pass-by-reference, but because in C
it's generally a nuisance to return stuff from functions, especially multiple
values, so you end up learning about pointers and/or pass-by-reference.

IOW, if you could erase the influence of previous languages would this FAQ
become "how can I return multiple things from a function" more often than it
would become "how can I modify an object from inside a function"?

-Dave

Tom Plunket

unread,
Jul 13, 2003, 3:39:01 AM7/13/03
to
Ian Bicking wrote:

> To be more specific, you would achieve the same effect with:
>
> def change(val):
> return val + 1
> i = change(i)

Yeah, thanks. I don't recall off-hand why it is that I wanted
this functionality, but something came up a few weeks ago that
seemed to beg for it. This was the solution that I used, but it
was non-optimal for some reason. The question came to mind
because of that global question posted just previously, to which
I made a good response if I may say so myself. :)

> There is no direct Python equivalent to the C++ function, for all
> sorts of reasons (most of them very deliberate).

Ok. I'd love to see the reasons for it. To me it just seems
like there's a somewhat arbitrary line between immutables and
mutables.

> Is there someplace in particular to reference people who need to
> learn about what Python variables are (that they are bindings,
> etc)?

Yeah, this is actually less a stumbling block, and more a desire
to want to bind to another variable instead of that variable's
value. I mean, if I do this:

a = [ ]
b = a
a.append(4)

print b
[ 4 ]

This seems inconsistent to me, although I understand that the two
variables are just binding to the same list. No different than
binding to the same tuple or integer or string, it's just that
changing the value of a tuple, an integer, or a string means
rebinding your variable to a different object.

I suppose one "solution" would be a class that wraps the value,
so the value can change but the object stays the same. Similar
is using a list, but these two options make it a little less
convenient, and one must exercise extreme caution lest one
accidentally reassign as an int instead of changing the internals
of the wrapper object.

> This question comes up in many forms all the time, particularly
> from people with a C background. Or rather, there are many

> questions all of which are answered by that explanation...

IMHO the variable binding discussion doesn't answer the question,
it just provokes more questions. :)

thanks to all who responded.

-tom!

Tom Plunket

unread,
Jul 13, 2003, 3:41:22 AM7/13/03
to
Dave Brueck wrote:

> Your response above (that the normal thing to do in Python is
> just return the modified value) made me wonder if most people are
> asking about pass-by-reference not because they want pass-by-
> reference, but because in C it's generally a nuisance to return
> stuff from functions, especially multiple values, so you end up
> learning about pointers and/or pass-by-reference.

In C++ it's trivial to return multiple values and pass-by-
reference is typically (at least, as far as I've seen) used to
pass immutables anyway, but sometimes it just seems like the
right tool for the job.

> IOW, if you could erase the influence of previous languages would
> this FAQ become "how can I return multiple things from a
> function" more often than it would become "how can I modify an
> object from inside a function"?

That's a good idea, although I would have to say that multiple
return values typically means that your function is doing too
many things. ;)

-tom!

Erik Max Francis

unread,
Jul 13, 2003, 3:55:22 AM7/13/03
to
Tom Plunket wrote:

> IMHO the variable binding discussion doesn't answer the question,
> it just provokes more questions. :)

But the answer to those questions is usually something ending with,
"Look, Python just doesn't handle variables the same way C++ does." :-)

--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
__ San Jose, CA, USA && 37 20 N 121 53 W && &tSftDotIotE

/ \ It seems like Karma's making his rounds
\__/ Kina

David McNab

unread,
Jul 13, 2003, 6:58:13 AM7/13/03
to
On Sat, 12 Jul 2003 13:53:35 -0700, Tom Plunket paused, took a deep
breath, then came out with:

> I want to do something along the lines of the following C++ code:
>
> void change(int& i)
> {
> i++;
> }

> Is there any way to do references like this in Python?

<snip>

In Python, basic types like strings and numbers are a weird exception to
the 'everything is an object' rule.

When you pass any other object in a function, the function gets a ref to
that object.

But when you pass a string or numeric object, the whole thing (not a ref)
gets passed.

Your best bet would be to create a wrapper class for numbers, store the
actual number in an attribute, and provide all the methods in Section
3.3.6 of the Python Reference Manual (__add__, __sub__ etc) to work on the
value attribute.

That way, you can use your numeric object in calculations, and when you
pass it to functions (like your 'change()' above), things will work as
expected. In fact, in most situations, it will look/feel/smell just like
a number.

But watch out for trying to assign to it, or using '+=' type operators -
they will replace your object with a plain number.

I attach below a sample class declaration for a numeric type which is
passable by reference (no need to do this for string, since you can just
use the UserString module).

Cheers
David

class myint:
def __init__(self, value):
self.value = value

def __getattr__(self, attr):
if attr in ['__repr__', '__add__', '__repr__', '__add__',
'__sub__', '__mul__', '__floordiv__', '__mod__',
'__divmod__', '__pow__', '__lshift__',
'__rshift__', '__and__', '__xor__', '__or__',
'__div__', '__truediv__', '__radd__', '__rsub__',
'__rmul__', '__rdiv__', '__rtruediv__',
'__rfloordiv__', '__rmod__', '__rdivmod__',
'__rpow__', '__rlshift__', '__rrshift__',
'__rand__', '__rxor__', '__ror__',
'__neg__',
'__pos__', '__abs__', '__invert__',
'__complex__', '__int__', '__long__',
'__float__', '__oct__', '__hex__', '__coerce__']:
return getattr(self.value, attr)

def __iadd__(self, other):
self.value += other
return self.value

def __isub__(self, other): self.value -= other
def __imul__(self, other): self.value *= other
def __idiv__(self, other): self.value /= other
def __itruediv__(self, other):
self.value = self.value.__itruediv__(other)
def __ifloordiv__(self, other): self.value = self.value.__itruediv__(other)
def __imod__(self, other): self.value = self.value.__imod__(other)
def __ipow__(self, other): self.value = self.value.__ipow__(other)
def __ilshift__(self, other): self.value = self.value.__ilshift__(other)
def __irshift__(self, other): self.value = self.value.__irshift__(other)
def __iand__(self, other): self.value = self.value.__iand__(other)
def __ixor__(self, other): self.value = self.value.__ixor__(other)
def __ior__(self, other): self.value = self.value.__ior__(other)

Dave Brueck

unread,
Jul 13, 2003, 7:50:46 AM7/13/03
to
On Sunday 13 July 2003 01:41 am, Tom Plunket wrote:
> Dave Brueck wrote:
> > Your response above (that the normal thing to do in Python is
> > just return the modified value) made me wonder if most people are
> > asking about pass-by-reference not because they want pass-by-
> > reference, but because in C it's generally a nuisance to return
> > stuff from functions, especially multiple values, so you end up
> > learning about pointers and/or pass-by-reference.
>
> In C++ it's trivial to return multiple values

Trivial but non-intuitive until you convince yourself "that's the way it is",
perhaps. :) What I mean is this: when you're just starting out you learn that
functions can return values like this:

int foo(int a, int b)
{
return a + b;
}

But the method for returning more than one thing is not a simple progression
from this pattern. Instead you learn and shift to a *completely* different
mechanism. In Python, however, you *can* continue along the original route as
well:

def foo(a, b, c):
return a+b, b+c

> > IOW, if you could erase the influence of previous languages would
> > this FAQ become "how can I return multiple things from a
> > function" more often than it would become "how can I modify an
> > object from inside a function"?
>
> That's a good idea, although I would have to say that multiple
> return values typically means that your function is doing too
> many things. ;)

Far from it:

lastName, firstName = line.split('\t')

(there are many, many, many such examples). This is also an example of what I
mean by "in C it's genreally a nuisance to return multiple values":

void split(char *pLine, char **ppLastName, char **ppFirstName) {}

Sadly, it's not uncommon to see one-off structures defined whose sole purpose
in life is to act as a go-between for functions. Ugh.

-Dave

Stephen Horne

unread,
Jul 13, 2003, 9:24:03 AM7/13/03
to
On Sun, 13 Jul 2003 00:55:22 -0700, Erik Max Francis <m...@alcyone.com>
wrote:

>Tom Plunket wrote:
>
>> IMHO the variable binding discussion doesn't answer the question,
>> it just provokes more questions. :)
>
>But the answer to those questions is usually something ending with,
>"Look, Python just doesn't handle variables the same way C++ does." :-)

And my traditional answer to that is... "yes, and the way that Python
handles variables is definitely a wart."

One of the few things I hate about Python is that mutable objects are
implicitly shared using a reference system whereas immutable objects
are not. It is unnecessarily confusing and error prone.

A system where all objects are copied unless a reference type is
explicitly applied (and with an assignment operators recognising
references on the LHS by default and assigns to the object rather than
the reference, though with an extra one which overwrites the
reference) seems much more logical to me. It even seems 'Pythonic' to
me. But it is much closer to C++ references than current Python
system.

Stephen Horne

unread,
Jul 13, 2003, 9:56:18 AM7/13/03
to
On Sun, 13 Jul 2003 05:50:46 -0600, Dave Brueck
<da...@pythonapocrypha.com> wrote:

>On Sunday 13 July 2003 01:41 am, Tom Plunket wrote:

>> In C++ it's trivial to return multiple values
>
>Trivial but non-intuitive until you convince yourself "that's the way it is",
>perhaps. :) What I mean is this: when you're just starting out you learn that
>functions can return values like this:
>
>int foo(int a, int b)
>{
> return a + b;
>}
>
>But the method for returning more than one thing is not a simple progression
>from this pattern. Instead you learn and shift to a *completely* different
>mechanism. In Python, however, you *can* continue along the original route as
>well:
>
>def foo(a, b, c):
> return a+b, b+c

You are not directly returning multiple values - you are returning a
tuple. You can return containers in C++ too. The only difference is
that Python makes working with tuples *much* easier - but its no more
a 'simple progression' than in C++. You still need to know about
tuples as well as returning values.

>> > IOW, if you could erase the influence of previous languages would
>> > this FAQ become "how can I return multiple things from a
>> > function" more often than it would become "how can I modify an
>> > object from inside a function"?

There's more to it than this.

Take the Pascal family of languages. These have an explicit
distinction between functions and procedures which is hidden in C and
Python.

In my view, the distinction between a procedure (an imperative tool
which may modify parameters in place) and a function (which returns a
value but - normally, at least - leaves its parameters unmodified) is
a useful one. Writing code to respect these conventions, even when the
language doesn't explicitly support it, has considerable benefits -
evaluation order in expressions becomes much less of an issue, for
instance, effectively eliminating at least one source of subtle
hard-to-trace errors.

Which suggests a new 'procedure' syntax for Python, either
automatically treating all parameters as references or providing a
syntax equivalent to the Pascal 'var'.

Oren Tirosh

unread,
Jul 13, 2003, 9:38:01 AM7/13/03
to
On Sun, Jul 13, 2003 at 10:58:13PM +1200, David McNab wrote:
> On Sat, 12 Jul 2003 13:53:35 -0700, Tom Plunket paused, took a deep
> breath, then came out with:
>
> > I want to do something along the lines of the following C++ code:
> >
> > void change(int& i)
> > {
> > i++;
> > }
>
> > Is there any way to do references like this in Python?
> <snip>
>
> In Python, basic types like strings and numbers are a weird exception to
> the 'everything is an object' rule.
>
> When you pass any other object in a function, the function gets a ref to
> that object.
>
> But when you pass a string or numeric object, the whole thing (not a ref)
> gets passed.

Numbers and strings are objects just like everything else in Python and
are passed by reference. The only difference is that they are *immutable*
objects so their value cannot be changed through that reference in a way
that will be visible to others who reference the same object. Under most
circumstances a reference to an immutable object is nearly indistingishable
from a value. But the id() builtin function or the 'is' operator quickly
reveal the difference.

There is no weird exception to any rule here. Some objects are mutable,
some are not. That's all.

Oren


Roy Smith

unread,
Jul 13, 2003, 10:30:05 AM7/13/03
to
Stephen Horne <intent...@blank.co.uk> wrote:
> One of the few things I hate about Python is that mutable objects are
> implicitly shared using a reference system whereas immutable objects
> are not. It is unnecessarily confusing and error prone.

There's a bit of confusion in the above regarding mutability vs. call by
reference (they're orthogonal ideas), but I think I know what you were
trying to say.

In ancient versions of Fortran, even constants (i.e. immutables) were
pass by reference. You could write something like this (forgive me if
I've forgotten some of the syntax details):

subroutine x (i)
i = 42
end

subroutine main
x (5)
write (6, 100) 5
100 format (1i6)
end

and it would print 42. There was a single instance of the constant 5
for main, and it was passed by reference to x(), which in turn changed
its value to 42. I don't remember if Fortan 66 did this, or if that
only happened in even older versions. Talk about confusing and error
prone!

The Python version of that would be:

def mutateString (s):
s = "some other string"

s ("foo")
print "foo"

If strings were pass by reference, the above would print "some other
string". Unless, of course, you got away from the idea that multiple
instances of a string constant with the same value are really the same
object, in which case:

x = "foo"
x is "foo"

would print 0 instead of 1 like it does now.

Aahz

unread,
Jul 13, 2003, 10:37:01 AM7/13/03
to
In article <iqm2hvs77lhe1m71v...@4ax.com>,

Stephen Horne <intent...@blank.co.uk> wrote:
>
>One of the few things I hate about Python is that mutable objects are
>implicitly shared using a reference system whereas immutable objects
>are not.

Well, that's incorrect. *ALL* Python objects are implicitly shared with
bindings. The difference is whether updating the value referenced by a
target requires *re*binding the target or simply updating an object.
--
Aahz (aa...@pythoncraft.com) <*> http://www.pythoncraft.com/

"Not everything in life has a clue in front of it...." --JMS

Stephen Horne

unread,
Jul 13, 2003, 11:11:37 AM7/13/03
to
On 13 Jul 2003 10:37:01 -0400, aa...@pythoncraft.com (Aahz) wrote:

>In article <iqm2hvs77lhe1m71v...@4ax.com>,
>Stephen Horne <intent...@blank.co.uk> wrote:
>>
>>One of the few things I hate about Python is that mutable objects are
>>implicitly shared using a reference system whereas immutable objects
>>are not.
>
>Well, that's incorrect. *ALL* Python objects are implicitly shared with
>bindings. The difference is whether updating the value referenced by a
>target requires *re*binding the target or simply updating an object.

Fine - nit-pick.

All you have proven is that it is the distinction between types that
get re-bound and those that don't (rather than the use of references)
that is unnecessarily confusing and error prone.

The wart remains, even if my description was wrong. And even that is a
dubious claim.

A Python user is interested in how an object behaves - not how it is
internally implemented in the interpreter. Immutable objects don't
behave as references - the internal use of references for immutable
objects is basically a lazy copying optimisation and, apart from
performace and a couple of other technicalities (e.g. the 'is'
operator), has no relevance. Certainly it has no relevance to the
point I was making.

Aahz

unread,
Jul 13, 2003, 12:19:08 PM7/13/03
to
In article <brs2hv8edfv0d1fch...@4ax.com>,

Stephen Horne <intent...@blank.co.uk> wrote:
>On 13 Jul 2003 10:37:01 -0400, aa...@pythoncraft.com (Aahz) wrote:
>>In article <iqm2hvs77lhe1m71v...@4ax.com>,
>>Stephen Horne <intent...@blank.co.uk> wrote:
>>>
>>>One of the few things I hate about Python is that mutable objects are
>>>implicitly shared using a reference system whereas immutable objects
>>>are not.
>>
>>Well, that's incorrect. *ALL* Python objects are implicitly shared with
>>bindings. The difference is whether updating the value referenced by a
>>target requires *re*binding the target or simply updating an object.
>
>Fine - nit-pick.

Believe it or not, it is *not* a nit-pick, it goes right to the core of
Python's design and philosophy.

>All you have proven is that it is the distinction between types that
>get re-bound and those that don't (rather than the use of references)
>that is unnecessarily confusing and error prone.

Only for people who insist on thinking about it through the lens of some
other way to do it.

>A Python user is interested in how an object behaves - not how it is
>internally implemented in the interpreter. Immutable objects don't
>behave as references - the internal use of references for immutable
>objects is basically a lazy copying optimisation and, apart from
>performace and a couple of other technicalities (e.g. the 'is'
>operator), has no relevance. Certainly it has no relevance to the
>point I was making.

That's precisely where you are wrong. Python's object model is
extremely strict and simple and orthogonal. Everything works exactly
the same way. Whether one can mutate a specific object is simply an
attribute of that object, rather than requiring a different syntax.
Trying to focus on the mutable/immutable distinction is what causes the
mental blowup -- keep your eye on the objects and bindings and you're
fine.

Noah

unread,
Jul 13, 2003, 1:21:56 PM7/13/03
to
Tom Plunket <to...@fancy.org> wrote in message news:<13t0hvsb7idh0g6ac...@4ax.com>...

As others have explained, you just return the value.
It's just a different point of view. Instead of
change (v)
you have:
v = change (v)

I was a C++ programmer in a former life and I remember being
annoyed at the lack of references in Python -- I mean, why would
something so obvious and cool as a reference variable be excluded, right?
Where people usually find themselves wanting references is
when they need to modify more than one value at once.
For example, consider a function to rotate a 3D point through
two angles, where x,y,z get modified by the rotate function:
rotate (x,y,z, theta, phi)
Here you just have to remember that Python can return more than one
value at once as a tuple. So you should expect the code to look like this:
x,y,z = rotate (x,y,z, theta, phi)
Your rotate() function would return a simple tuple as:
return (x,y,z)

After I unlearned the C++ idiom I decided I liked the Python idiom better.
It's a teensy bit more verbose, but it is far more clear as to what
is going on. Your inputs and output are clearly defined. With C++ references
you have to look up the function definition to know which variables in modified.

Yours,
Noah

Aahz

unread,
Jul 13, 2003, 1:40:13 PM7/13/03
to
In article <13t0hvsb7idh0g6ac...@4ax.com>,

Tom Plunket <to...@fancy.org> wrote:
>
>I want to do something along the lines of the following C++ code:
>
>void change(int& i)
>{
> i++;
>}

class Counter:
def __init__(self, start=0):
self.counter = start
def inc(self, increment=1):
self.counter += increment

def change(counter):
counter.inc()

There's no need to get into all the special methods required to
implement a number type, and it's a Bad Idea to use a random container
object. Just pass around a mutable class instance, and your code
becomes simpler and clearer.

Stephen Horne

unread,
Jul 13, 2003, 1:51:47 PM7/13/03
to
On 13 Jul 2003 12:19:08 -0400, aa...@pythoncraft.com (Aahz) wrote:

>Whether one can mutate a specific object is simply an
>attribute of that object, rather than requiring a different syntax.
>Trying to focus on the mutable/immutable distinction is what causes the
>mental blowup -- keep your eye on the objects and bindings and you're
>fine.

That's exactly it - you have to focus on whether an object is mutable
or immutable for that exact reason.

While I admit I'm not sure, I believe that in early versions of Python
immutable values literally were copied. Mutable types were made
mutable because of efficiency concerns about copying overheads that
would occur otherwise. If an object is large enough that it is
worthwhile modifying items within it in-place then it tends to be
worthwhile trying to avoid copying overheads, even though these two
aspects of 'mutability' are actually quite distinct in principle.

Actually, I'm convinced there are some flaws in Guidos own logic
*unless* this is the case. Take for instance this...

http://www.python.org/search/hypermail/python-1992/0292.html

"""
<A> They serve different purposes. Lists can get quite long, they are
generally built incrementally, and therefore have to be mutable.
Tuples on the other hand are generally short and created at once.


<Q> Then why can't tuples be mutable and serve both purposes?


<A> Imagine a graphics class that stores coordinates of graphical
objects as tuples. It may also store rectangles as a tuple of points,
etc. If tuples were mutable, the class would have to store copies of
all points and rectangles it receives, since otherwise a caller who
creates a point variable, passes its value to the graphics class, and
later changes the point for its own use (e.g., to create another
graphical object with slightly different coordinates) might violate
the internal consistency of the graphics class. Note that most
callers woouldn't modify the points, but the graphics class has no way
to tell, so it has to make the copies anyway. (And now imaging the
software is actually layered in such a way that coordinates are passed
down several levels deep...)
"""

So what?

As things are, the points could be stored using a list of tuples, with
each tuple representing a point. When you store a new point in the
list, you don't immediately make a copy (so if the supplier of the
point immediately discards it, no copying is needed at all except for
pointers) so it is efficient - yet you are still guarenteed that
external processing will not mutate the value you hold in your list.

Fine.

But that can be achieved equally well by applying a copy-on-write
system to *all* types, without a distinction between mutable and
immutable for this purpose.

Equally, you could use the same rationale for storing items which
Python classes as mutable instead of these point tuples. If you have
an object which stores class instances or dictionaries or lists for
you, you need to store copies as - just as Guido recognised for the
tuple case - your object doesn't know for sure what the caller is
going to do with those objects after passing them in as parameters.

This makes no sense to me *unless* there were other reasons for the
mutable/immutable distinction. If lists had copy-on-write semantics,
they could still be mutable (ie support in-place modification) yet
there would be no need to make early copies. Tuples would be redundant
as their only distinctive feature would be their lack of support for
in-place modifications. It only makes sense if the copy-on-write for
immutable values hadn't been implemented when the distinction was
created - if immutables did not use references, but were always copied
immediately on assignment - so that the referencing mechanism need
never worry about copy-on-write at all.


But it is worse than just being an arbitrary and pointless
distinction...

Back when PEP238 was being 'debated', a major argument in favor of the
change was that there is no legitimate case where a function would
need to either do 'true' division or integer division depending on the
argument type. The type of division needed depends on the purpose of
the function, and behaviour shouldn't change just because someone
passes an integer into a function that expects a real or visa versa.

Apply the same logic to mutable and immutable types.

Tell me one case where it is sensible for a function to behave such
that whether the caller sees a change in a variable it passed as its
argument should depend on the type.

Tell me one case where an object storing values should care about
callers mutating values it holds *only* for certain types.

I doubt you can.

This is an arbitrary distinction created for historic reasons that
have long since vanished (apart, of course, from backward
compatibility and psychological inertia), given that copy-on-write is
implemented for immutable objects anyway. And the fact that immutable
values do an excellent job of implementing the common semantics of
most imperitive languages (i.e. assignment sets the LHS to something
that can be treated as a distinct copy) whereas mutable types behave
in a fundamentally different way is quite simply a wart -
inconsistent, confusing and error-prone behaviour.

Terry Reedy

unread,
Jul 13, 2003, 3:07:23 PM7/13/03
to

"David McNab" <postm...@127.0.0.1> wrote in message
news:pan.2003.07.13....@127.0.0.1...

> In Python, basic types like strings and numbers are a weird
exception to
> the 'everything is an object' rule.

In Java perhaps, but NOT in Python. This is WRONG, WRONG, WRONG.
Please do not muddy the waters like this.

In Python, most builtin types are immutable. The two mutable builtin
types are lists and dicts. Instances of user-defined classes are also
mutable by default.

>When you pass any other object in a function,

>But when you pass a string or numeric object, [incorrect statement
clipped]

In Python, everything is 'passed' to functions the same way: first,
the argument expressions are evaluated one at a time, left to right.
In the typical case (number of argument expressions == number of
positional parameters), the resulting objects are then bound to the
corresponding parameter names, left to right, in the local namespace
of the function. (Or, if you prefer, the names are bound ...) The
type of the argument objects is not looked at.

How a particular interpreter performs name binding is its own
business, as long as the specified semantics are implemented. What
CPython does may or may not be the same as Jython or any other actual
or potential computer implementation. What any computer does is
probably significantly different from what human interpreters do.

Terry J. Reedy


Donn Cave

unread,
Jul 13, 2003, 3:24:14 PM7/13/03
to
Quoth Stephen Horne <intent...@blank.co.uk>:

| On 13 Jul 2003 12:19:08 -0400, aa...@pythoncraft.com (Aahz) wrote:
|
|> Whether one can mutate a specific object is simply an
|> attribute of that object, rather than requiring a different syntax.
|> Trying to focus on the mutable/immutable distinction is what causes the
|> mental blowup -- keep your eye on the objects and bindings and you're
|> fine.
|
| That's exactly it - you have to focus on whether an object is mutable
| or immutable for that exact reason.
|
| While I admit I'm not sure, I believe that in early versions of Python
| immutable values literally were copied. Mutable types were made
| mutable because of efficiency concerns about copying overheads that
| would occur otherwise. If an object is large enough that it is
| worthwhile modifying items within it in-place then it tends to be
| worthwhile trying to avoid copying overheads, even though these two
| aspects of 'mutability' are actually quite distinct in principle.

Sure, mutable values literally are copied today. If you have a tuple
of time.localtime(x), for example, and you want that value but with
tm_mday incremented, then you must copy the tuple to do that (except
for tm_mday, for which you substitute your own value.) It is indeed
inefficient - OK for this purpose but not for large sequences, and
there we tend to prefer a mutable list.

That's the efficiency argument. Assigment never copied values, in
any version of Python that anyone cared about. We just don't want
big immutable arrays that have to be copied just to change a single
value. There isn't a tuple analogue for the dictionary because it
wouldn't be so generally useful (the recently implemented struct
tuple would have been nice to have earlier, though.)

He's quite right, the notion of mutability is a red herring. It
isn't that no one cares - the propagation of state changes in a
program is critical to the operation of the program, and to reasoning
about how the program will operate.

It's just that when you're trying to come to grips with how assignment
and argument passing works in Python, you don't want to have people
start explaining things in these terms (``see, this object is mutable
and that one isn't''), because you will understandably but incorrectly
apply that to assignment and argument passing. Mutability in Python
has no effect on assignment and argument passing, it is just an attribute
of the passed or assigned object.

Donn Cave, do...@drizzle.com

Stephen Horne

unread,
Jul 13, 2003, 3:39:56 PM7/13/03
to
On Sun, 13 Jul 2003 15:07:23 -0400, "Terry Reedy" <tjr...@udel.edu>
wrote:

>How a particular interpreter performs name binding is its own
>business, as long as the specified semantics are implemented.

You could use the same argument to rationalise a language which used
the + operator to express subtraction.

The fact is that 'assignment' has a common meaning separate from the
choice of programming language, and that the way Python handles name
binding means that meaning is not respected by Python for mutable
objects.

>What any computer does is
>probably significantly different from what human interpreters do.

And using references with a copy-on-write or lazy-assignment system is
different to immediate copying of values, but that is irrelevent as
both systems respect the common meaning of assignment.

Python, however, does not respect this meaning. It uses an arbitrary
distinction based on whether or not the object has internals that can
be usefully in-place modified, and uses that distinction to vary the
effect of assignment in an arbitrary, inconsistent and error-prone
way. The need for a distinct tuple type is a symptom of the arbitrary
nature of this.

I've already posted too much on this, so this is going to be the end
to it. But Pythons semantics with regard to mutable and immutable
objects are simply bizarre. A historic justification may be plausible
and backward compatibility is then an important issue, but I really
cannot accept claims that Python is doing the right thing here.

Ian Bicking

unread,
Jul 13, 2003, 3:48:09 PM7/13/03
to
On Sun, 2003-07-13 at 12:51, Stephen Horne wrote:
> On 13 Jul 2003 12:19:08 -0400, aa...@pythoncraft.com (Aahz) wrote:
>
> >Whether one can mutate a specific object is simply an
> >attribute of that object, rather than requiring a different syntax.
> >Trying to focus on the mutable/immutable distinction is what causes the
> >mental blowup -- keep your eye on the objects and bindings and you're
> >fine.
>
> That's exactly it - you have to focus on whether an object is mutable
> or immutable for that exact reason.

No you don't! Mutable and immutable objects act the same with respect
to assignment. However, because you cannot change a immutable object in
place, to get a different value you must rebind. You must *use* mutable
and immutable objects differently -- but that is not surprising, because
they are obviously very different objects! You have to use integers and
lists differently in part because one is mutable and the other isn't --
but mostly because one is a number and the other is a list. Different
objects are different!

Python is not novel in the way it deals with variables. Scheme and
Smalltalk, for instance, act exactly the same, as do many other
dynamically typed languages (though there are different opinions on
whether strings should be mutable -- but it's agreed there has to be
some immutable string-like type, e.g. symbol). The reason you are
getting this reaction is that anyone that comes from those backgrounds
thinks you are crazy, as does anyone who has embraced the Python model.
This isn't a funny little feature, this is the way all strong,
dynamically typed languages work.

> While I admit I'm not sure, I believe that in early versions of Python
> immutable values literally were copied. Mutable types were made
> mutable because of efficiency concerns about copying overheads that
> would occur otherwise. If an object is large enough that it is
> worthwhile modifying items within it in-place then it tends to be
> worthwhile trying to avoid copying overheads, even though these two
> aspects of 'mutability' are actually quite distinct in principle.

The problem you have is you are still thinking of variables as slots,
which is not correct. Variables in Python are bindings. Assignment
never copies anything, or creates anything except for changing the
variable to point to a different address location. *Every* Python
assignment (a=b) is like the C assignment (a=&b).

> Tell me one case where it is sensible for a function to behave such
> that whether the caller sees a change in a variable it passed as its
> argument should depend on the type.

Generally a function takes either immutable values (e.g., ints and
floats) or mutable values for a certain argument.

However, there is a class of operations which are generally operate in
an immutable manner, that is, create copies of the objects instead of
changing them in place. So even though lists are mutable, list
concatenation does not mutate, and in general adding two things (with +)
will not mutate either object. Immutable values, by design, do not have
the same methods and operations as the mutable counterparts (or at least
the mutating methods of those mutable objects). *That* would be a
design bug.

> Tell me one case where an object storing values should care about
> callers mutating values it holds *only* for certain types.

Objects don't *store* values, they *refer* to values. You are still
thinking like you're in C (or C++). This is why you are having a
problem.

Ian

Ian Bicking

unread,
Jul 13, 2003, 3:52:59 PM7/13/03
to
On Sun, 2003-07-13 at 08:56, Stephen Horne wrote:>
> You are not directly returning multiple values - you are returning a
> tuple. You can return containers in C++ too. The only difference is
> that Python makes working with tuples *much* easier

Of course, anything you can do in Python you can do in any other
language. The *whole point* is that Python is so much easier. Don't
worry so much about every equivalent feature or about translating every
C++ idiom to Python. Just write your programs -- they'll be different
from C++, but that's okay.

Ian

Erik Max Francis

unread,
Jul 13, 2003, 4:42:23 PM7/13/03
to
David McNab wrote:

> In Python, basic types like strings and numbers are a weird exception to
> the 'everything is an object' rule.
>
> When you pass any other object in a function, the function gets a ref to
> that object.
>
> But when you pass a string or numeric object, the whole thing (not a ref)
> gets passed.


This is completely incorrect. On the contrary, builtin types are
handled exactly uniformly in Python. The only difference here is that
the builtin types that you've listed, along with some others, are
immutable, so you cannot change them if you have a reference to them.

Contrast this to, say, Java, where there really is a solid distinction
between builtin fundamental types, like int and long, and actual object
types, derived from java.lang.Object, which are all passed by reference.
Python doesn't make this distinction.


--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
__ San Jose, CA, USA && 37 20 N 121 53 W && &tSftDotIotE

/ \ But who shall dwell in these worlds if they be inhabited?
\__/ Johannes Kepler

Tim Peters

unread,
Jul 13, 2003, 4:57:18 PM7/13/03
to
[Stephen Horne]
> ...

> The fact is that 'assignment' has a common meaning separate from the
> choice of programming language,

Well, that's not a fact, although there may be much commonality among the
(necessarily few, if you believe this) programming languages you've used.
Python's assignment semantics are in fact common among languages
higher-level than those of the Fortran/COBOL/Algol/C ilk. For examples,
Lisp, SNOBOL4, Scheme, Smalltalk and Icon are (very) much like Python in
this respect. So is Java in the end, although the underlying machinery is
more complicated there.

> and that the way Python handles name binding means that meaning is not
> respected by Python for mutable objects.

Python's assignment semantics don't vary according to object type.

> ...


> Python, however, does not respect this meaning.

This doesn't say more than that Python works differently than the languages
you've used. It really isn't a question of respect <wink>.

> It uses an arbitrary distinction based on whether or not the object
> has internals that can be usefully in-place modified, and uses that
> distinction to vary the effect of assignment in an arbitrary,
> inconsistent and error-prone way.

It's deliberate and thoroughly consistent. Any assignment semantics are
error-prone in some contexts, though (Python's included -- side effects are
like that). The simplicity and absolute consistency of Python-style
assignment semantics are probably easiest for first-time programmers to pick
up, and certainly dead easy for people coming from Lisp (etc) to pick up --
people coming from C (etc) often struggle with inappropriate expectations at
first.

> The need for a distinct tuple type is a symptom of the arbitrary
> nature of this.

Python's assignment semantics have nothing to do with mutability versus
immutability. The latter is a type-dependent distinction; assignment
semantics in Python don't depend on object type in any way.

> ...


> I've already posted too much on this, so this is going to be the end
> to it. But Pythons semantics with regard to mutable and immutable
> objects are simply bizarre.

Hmm. Mutable objects can be mutated, and immutable objects cannot be
mutated. That doesn't seem bizarre.

> A historic justification may be plausible and backward compatibility
> is then an important issue, but I really cannot accept claims that
> Python is doing the right thing here.

Well, I can assure you Guido wouldn't change anything about Python's
assignment semantics if were able to do it all over from scratch. That's a
puzzle for you to work out, then: is Guido unique, or are all Dutch people
that stupid <wink>?


Ian Bicking

unread,
Jul 13, 2003, 4:05:38 PM7/13/03
to
On Sun, 2003-07-13 at 14:39, Stephen Horne wrote:
> The fact is that 'assignment' has a common meaning separate from the
> choice of programming language,

This just isn't true. The C++ assignment operator is not at all like
the Python assignment statement. Python variables are not like C++
variables, no surprise assignment is different too. If you used
languages outside of C++ and its like (e.g., Pascal), you would find
Python's behavior common.

(Admittedly, some confusion may occur because these very different
operations use the same syntax:

x = 10
x[0] = 10
obj.x = 10

The second and third are entirely different from the first.)

Ian

Stephen Horne

unread,
Jul 13, 2003, 5:08:07 PM7/13/03
to
On 13 Jul 2003 14:48:09 -0500, Ian Bicking <ia...@colorstudy.com>
wrote:

In computer science, a variable is a named binding to a value.
Operations on that variable may rebind it to a different value, but
values don't change behind your back. A pointer is, in effect, a value
which indirectly refers to another (possibly anonymous) variable. A
pointer is something you specifically request, and by doing so you
allow that the 'variable' being indirectly referenced may be modified
by something else that has no direct access to your pointer value (via
your named variable or via copys or pointers-to your pointer held
elsewhere).

Python should respect that.

If you claim that it does, then the values to which we currently
associate the type name 'list', 'dictionary' and 'class instance' are
badly named. They should be called 'pointer to list', 'pointer to
dictionary' and 'pointer to class instance'. And if you want to call
those references and make the dereferencing implicit, fine. Equally,
if you want to implement variable binding using references and using
copy-on-write to implement lazy copying (which does not violate the
standard computer-theory semantics of the binding to values - only the
binding to the implementation of values ie memory locations) then
equally fine.

However, even if the names included the 'pointer to' prefix so that
they actually described the real behaviours of the values, this still
raises two important questions...

1. Why are the values of mutable objects always forced to be accessed
via a pointer (or reference or whatever)?

Note that I am referring to a computer science, semantic
pointer/reference/whatever - not to any pointers or references that
may be used in the implementation of the binding of variables to
values. The use, behind the scenes, of lazy copying as an optimisation
is irrelevant to the computer science principles.

2. Why is there no way to reference an immutable object via a
pointer, other than stuffing it into a mutable object designed for
some purpose other than simple pointer behaviour?

The truth is that this system is arbitrary, and that therefore this
excuse is invalid.

>The problem you have is you are still thinking of variables as slots,
>which is not correct. Variables in Python are bindings. Assignment
>never copies anything, or creates anything except for changing the
>variable to point to a different address location. *Every* Python
>assignment (a=b) is like the C assignment (a=&b).

The problem is that you are confusing implementation with semantics.
The meanings of 'variable', 'value', 'assignment' etc are defined by
computer science. Whether you arbitrarily change the meaning of
'assignment' or whether you arbitrarily change the meaning of
'variable', it amounts to the same thing.

>
>> Tell me one case where it is sensible for a function to behave such
>> that whether the caller sees a change in a variable it passed as its
>> argument should depend on the type.
>
>Generally a function takes either immutable values (e.g., ints and
>floats) or mutable values for a certain argument.
>
>However, there is a class of operations which are generally operate in
>an immutable manner, that is, create copies of the objects instead of
>changing them in place. So even though lists are mutable, list
>concatenation does not mutate, and in general adding two things (with +)
>will not mutate either object. Immutable values, by design, do not have
>the same methods and operations as the mutable counterparts (or at least
>the mutating methods of those mutable objects). *That* would be a
>design bug.

You miss my point. Your argument would equally apply to the need for
an integer-specific division operator, for instance. Its all about how
one function reacts in response to varying input. If you pass a
mutable value to a function which expects an immutable one, you get an
error. If you pass an immutable value to a function which expects a
mutable one, you get an error. There is no good reason for a function
to react to the distinction as evidenced by your own observation that
what actually happens (and what should happen) is that you have two
distinct variants of the function.

>> Tell me one case where an object storing values should care about
>> callers mutating values it holds *only* for certain types.
>
>Objects don't *store* values, they *refer* to values. You are still
>thinking like you're in C (or C++). This is why you are having a
>problem.

No it is not. I'm thinking in terms of computer science, in which
terms like 'variable', 'value' and 'assignment' are abstract concepts
independent of the way in which they are implemented in a programming
language.

One way or the other, Python is currently choosing not to respect the
computer science definition of those terms. It may have historic and
backward-compatability reasons, but that does not change the facts.
This deviation from computer science definitions, whatever the excuse,
is arbitrary, confusing and error prone. That is my problem.

Terry Reedy

unread,
Jul 13, 2003, 5:16:08 PM7/13/03
to

"Stephen Horne" <intent...@blank.co.uk> wrote in message
news:b8c3hvsesjoumiboo...@4ax.com...

> On Sun, 13 Jul 2003 15:07:23 -0400, "Terry Reedy" <tjr...@udel.edu>
> wrote:
>
> >How a particular interpreter performs name binding is its own
> >business, as long as the specified semantics are implemented.
>
> You could use the same argument to rationalise a language which used
> the + operator to express subtraction.

Bogus comparison with name binding. I am not aware that Python does
anything quite so backwards.

> The fact is that 'assignment' has a common meaning separate from the
> choice of programming language, and that the way Python handles name
> binding means that meaning is not respected by Python for mutable
> objects.

From what others have posted, Python is not the only language in which
'name=object' means "assign 'name' to that object". This is much
closer to the common idea of object having names than the idea that
names can only name value holders (blocks of linear memory) and not
values or objects themselves.

Terry J. Reedy


Stephen Horne

unread,
Jul 13, 2003, 5:20:33 PM7/13/03
to
On 13 Jul 2003 15:05:38 -0500, Ian Bicking <ia...@colorstudy.com>
wrote:

>On Sun, 2003-07-13 at 14:39, Stephen Horne wrote:


>> The fact is that 'assignment' has a common meaning separate from the
>> choice of programming language,
>
>This just isn't true. The C++ assignment operator is not at all like
>the Python assignment statement. Python variables are not like C++
>variables, no surprise assignment is different too. If you used
>languages outside of C++ and its like (e.g., Pascal), you would find
>Python's behavior common.

Think again.

When I say "'assignment' has a common meaning separate from the choice
of programming language" I assumed you would get the hint. I'm not
referring to some specific other programming language, of which I have
used many - and not all of them imperative. I am referring to the
definitions in computer theory, which do not relate to any specific
programming language but actually apply to all of them, irrespective
of paradigm and everything else.

Of course, if you really believe that pointer/reference behaviour
should be arbitrarily tied to mutability then you can claim that I am
wrong, but you still can't claim the high ground as this is still an
arbitrary and bizarre thing to do. The ability to change part or all
of a value in-place has nothing to do with whether that value is
referenced using a pointer or whatever in computer theory - any link
between pointers/references and mutability should be related to the
implementation of the language - not the semantics.

So much for dropping out of the discussion, but I hate it when people
make false claims about my beliefs, making me out to be ignorant, when
it is *not* *me* who is missing the point.

Stephen Horne

unread,
Jul 13, 2003, 5:41:20 PM7/13/03
to
On Sun, 13 Jul 2003 17:16:08 -0400, "Terry Reedy" <tjr...@udel.edu>
wrote:

>> You could use the same argument to rationalise a language which used


>> the + operator to express subtraction.
>
>Bogus comparison with name binding. I am not aware that Python does
>anything quite so backwards.

Using an exaggeration as an analogy. Possibly. Though terms like
'assignment', 'variable' and 'value' seems pretty fundamental to me,
so the exaggeration is not that huge.

>> The fact is that 'assignment' has a common meaning separate from the
>> choice of programming language, and that the way Python handles name
>> binding means that meaning is not respected by Python for mutable
>> objects.
>
>From what others have posted, Python is not the only language in which
>'name=object' means "assign 'name' to that object". This is much
>closer to the common idea of object having names than the idea that
>names can only name value holders (blocks of linear memory) and not
>values or objects themselves.

Many languages have *explicit* ways to create what computer science
calls pointers. Sometimes they have implicit dereferencing. Sometimes
they come prepackaged in a 'pointer to' or 'reference to' style
object. But the fact that you are dealing with something that
semantically behaves as a pointer is always explicit in some way or
another.

Or rather, it should be. The fact that a few other languages are
broken in much the same way does not mean that Python is doing the
right thing. The right thing does not mean imitating Java or whatever
any more than it means imitating C++.

If you want a good example to imitate, though, look to Haskell. I
don't know how it binds variables to values, but I do know that in
general it can't a simple mapping from identifier to memory location.
Even so, I don't care. Why should I? The implementation of the binding
is irrelevant - I only care that the value bound to the variable is
the one that I specified and that it doesn't get changed behind my
back.

Stephen Horne

unread,
Jul 13, 2003, 5:52:46 PM7/13/03
to
On Sun, 13 Jul 2003 16:57:18 -0400, "Tim Peters" <tim...@comcast.net>
wrote:

>[Stephen Horne]
>> ...
>> The fact is that 'assignment' has a common meaning separate from the
>> choice of programming language,
>
>Well, that's not a fact, although there may be much commonality among the
>(necessarily few, if you believe this) programming languages you've used.
>Python's assignment semantics are in fact common among languages
>higher-level than those of the Fortran/COBOL/Algol/C ilk. For examples,
>Lisp, SNOBOL4, Scheme, Smalltalk and Icon are (very) much like Python in
>this respect. So is Java in the end, although the underlying machinery is
>more complicated there.
>
>> and that the way Python handles name binding means that meaning is not
>> respected by Python for mutable objects.
>
>Python's assignment semantics don't vary according to object type.

OK then. With reference to another of my posts...

1. Why are dictionarys called dictionaries (rather than references to
dictionarys or whatever)? Similar for lists and class instances.

2. Why are the values of mutable objects always forced to be accessed


via a pointer (or reference or whatever)?

Note - whether it makes sense to allow in-place changes to part or all
of a value is not the same as whether it makes sense to reference that
value indirectly.

3. Why is there no way to reference an immutable object via a


pointer, other than stuffing it into a mutable object designed for
some purpose other than simple pointer behaviour?

This excuse is, as I already said, invalid.

>Well, I can assure you Guido wouldn't change anything about Python's
>assignment semantics if were able to do it all over from scratch. That's a
>puzzle for you to work out, then: is Guido unique, or are all Dutch people
>that stupid <wink>?

Your words, not mine. I simply point out that no-one, BDFL or
otherwise, can be perfect.

Jimmy Retzlaff

unread,
Jul 13, 2003, 5:45:45 PM7/13/03
to
Stephen Horne wrote:
>...

>Of course, if you really believe that pointer/reference behaviour
>should be arbitrarily tied to mutability then you can claim that I am
>wrong, but you still can't claim the high ground as this is still an
>arbitrary and bizarre thing to do. The ability to change part or all
>of a value in-place has nothing to do with whether that value is
>referenced using a pointer or whatever in computer theory - any link
>between pointers/references and mutability should be related to the
>implementation of the language - not the semantics.
>...

Assignment, and therefore parameter passing, is entirely consistent
between mutable/immutable types. That is to say, assignment and
mutability are orthogonal and unrelated concepts in Python, just as you
suggest they should be. Perhaps some folks who only partially understand
Python's parameter passing semantics would be surprised by:

>>> def f(x):
... x = [4, 5, 6]
...
>>> a = [1, 2, 3]
>>> f(a)
>>> print a
[1, 2, 3]

Note that the assignment within f did not affect a in any way despite
the fact that a was an instance of a mutable type. It works exactly the
same way with a tuple.

With similar consistency you can call any method on an object passed as
a parameter. Where the distinction between mutable and immutable types
comes in is that there don't happen to be any methods of immutable
objects that actually modify the value of the object; mutable objects do
offer such methods. For example, tuples don't have "append" or "sort"
methods that modify the object's value in place, but lists do.

Now where some more of the assignment related confusion might come in is
with things like this:

>>> def f(x):
... x[0] = 10
...
>>> a = [1, 2, 3]
>>> f(a)
>>> print a
[10, 2, 3]

The body of f may look like it contains an assignment, but that's not
the typical name-binding that is referred to when discussing assignment
(or parameter passing) in Python. That is really just syntactic sugar
for calling a method of the parameter x, namely the __setitem__ method.
List objects are mutable and so, by definition, some methods like
__setitem__ will change their value. Tuples don't have __setitem__
methods so the above assignment in f won't work if you pass in a tuple.
Note that the same "assignment" outside of f wouldn't work for a tuple
either; this is a property of the tuple (i.e., it doesn't offer a
__setitem__ method), not of Python's parameter passing / assignment
semantics.

Jimmy

Jack Diederich

unread,
Jul 13, 2003, 5:16:55 PM7/13/03
to
On Sun, Jul 13, 2003 at 03:05:38PM -0500, Ian Bicking wrote:
> On Sun, 2003-07-13 at 14:39, Stephen Horne wrote:
> > The fact is that 'assignment' has a common meaning separate from the
> > choice of programming language,
>
> This just isn't true. The C++ assignment operator is not at all like
> the Python assignment statement. Python variables are not like C++
> variables, no surprise assignment is different too. If you used
> languages outside of C++ and its like (e.g., Pascal), you would find
> Python's behavior common.
>

C++ is the only language that has the same semantics as C++.

I was a long time C++ guy and my a-ha moment was when I realized that the
GoF's "Design Patterns" were not all universal -- some are C++ specific.
Trying to force Python semantics into a C++ world view will leave you feeling
empty every time. Drink the koolaid, python has a short learning curve.
If this is a problem - whatever you do - DONT TRY TO LEARN LISP.

If you want a more polished C++, use Java. Python is in a different class
of languages.

-jack

Martin v. Löwis

unread,
Jul 13, 2003, 6:01:28 PM7/13/03
to
Stephen Horne <intent...@blank.co.uk> writes:

> >This just isn't true. The C++ assignment operator is not at all like
> >the Python assignment statement. Python variables are not like C++
> >variables, no surprise assignment is different too. If you used
> >languages outside of C++ and its like (e.g., Pascal), you would find
> >Python's behavior common.

[...]


> The ability to change part or all
> of a value in-place has nothing to do with whether that value is
> referenced using a pointer or whatever in computer theory - any link
> between pointers/references and mutability should be related to the
> implementation of the language - not the semantics.

So you think "assignment" is about "changing values"? This is the case
in C and C++, but not the case in Java (atleast for objects), and Python.

In Python, assignment changes variables, not values. This is something
fundamentally different. In Python (and many other languages),
variables are independent of their value (and vice versa). Variables
are *associated* with a value, instead of *being* that value. Then,
assignment changes that association - not the value itself.

> So much for dropping out of the discussion, but I hate it when people
> make false claims about my beliefs, making me out to be ignorant, when
> it is *not* *me* who is missing the point.

I'm uncertain what your point is, however, I do observe that computer
theory has a different view of what assignments are than what I think
your view is.

Regards,
Martin

Martin v. Löwis

unread,
Jul 13, 2003, 6:17:19 PM7/13/03
to
Stephen Horne <intent...@blank.co.uk> writes:

> 1. Why are dictionarys called dictionaries (rather than references to
> dictionarys or whatever)? Similar for lists and class instances.

Because they are the values themselves, instead of being references to
values. These values (like all other values) are objects, though,
which means they have identity, state, and behaviour.

You might be thinking of values which only have state and
behaviour. Such values are not supported in Python - objects always
have an identity.

> 2. Why are the values of mutable objects always forced to be accessed
> via a pointer (or reference or whatever)?

Because all variables are references to objects. In Python, you cannot
have a variable that *is* a value - variables are always *bound* to
values, and accessing the variable yields the associated value. The
values exist independently from the variables they are bound to, and a
single value may be bound to different variables.

> 3. Why is there no way to reference an immutable object via a
> pointer, other than stuffing it into a mutable object designed for
> some purpose other than simple pointer behaviour?

But there is: If I do

a = 1
b = a

then b *refers* the same value that a refers to. That is, the values
associated with a and b have the same identity.

> This excuse is, as I already said, invalid.

Which excuse? You have only listed questions in this message, not
excuses.

Regards,
Martin

Bryan

unread,
Jul 13, 2003, 6:42:21 PM7/13/03
to

> 3. Why is there no way to reference an immutable object via a
> pointer, other than stuffing it into a mutable object designed for
> some purpose other than simple pointer behaviour?
>

>>> a = (1, 2, 3)
>>> b = a
>>> id(a)
15471760
>>> id(b)
15471760
>>> print b[1]
2
>>>


i just referenced an immutable object via a "pointer" and i __did_not__
stuff it into a mutable object as you say.
a and b "point" to the same object.

bryan


Bengt Richter

unread,
Jul 13, 2003, 6:46:41 PM7/13/03
to
On Sun, 13 Jul 2003 16:11:37 +0100, Stephen Horne <intent...@blank.co.uk> wrote:

>On 13 Jul 2003 10:37:01 -0400, aa...@pythoncraft.com (Aahz) wrote:
>
>>In article <iqm2hvs77lhe1m71v...@4ax.com>,
>>Stephen Horne <intent...@blank.co.uk> wrote:
>>>
>>>One of the few things I hate about Python is that mutable objects are
>>>implicitly shared using a reference system whereas immutable objects
>>>are not.
>>
>>Well, that's incorrect. *ALL* Python objects are implicitly shared with
>>bindings. The difference is whether updating the value referenced by a
>>target requires *re*binding the target or simply updating an object.
>
>Fine - nit-pick.

Well, it *is* a (very) significant nit ;-)

>
>All you have proven is that it is the distinction between types that
>get re-bound and those that don't (rather than the use of references)
>that is unnecessarily confusing and error prone.

I suspect you are reading some Python statements as if they were C or C++.

Python name assignment does not do anything to an object. It just creates
an alias name for an object. It may reuse an existing name, but that only
changes the meaning of that name as an alias, it does not affect the object
that the name was previously an alias for.

You can of course have other assignment targets than plain names. In fact,
a "plain name" is just the simplest expression for an assignment target.
But whatever the target expression evaluates to, what gets put "there" is
a reference to an object, not an object itself.

The confusion, ISTM, is in what to think of as "there." "There" is definitely
not a memory space for a Python object representation or "value".

The most accurate (UIAM) C concept would be a "there" of type PyObject* -- i.e.,
a pointer variable that points to the representation of some kind of Python object.

We don't have to know the implementation details to use the idea that the left hand
side of a Python assignment is an *expression* (even if a single name) that yields
a place to put a reference (effectively a pointer) to the object created by evaluating
the expression on the right hand side.

A C programmer will tend to think that a symbol on the left is a static expression
indicating a specific fixed memory space (static address or stack frame offset). But in Python
it is first of all a dynamic expression (though an unqualified target name can only have its "there"
be in the local or global namespace, and the choice between those is made statically
(at least w.r.t. a given level of compiling/exec-ing).

In C terms, the Python assignment target expression always evaluates to a place to put a pointer,
never a place to put object representation bits. Of course, "a place to put a pointer"
may be *inside* an object. And such inside places are identified by target expressions
such as x[2] or x.a or x[2]().b[3] etc. Even a bare name really does identify a place inside
an object -- i.e., inside the local or global dict associated with the context.

The "place" identified by x= after a global x declaration (or just in global scope) will be the
same place as globals()['x']= unless someone has subverted something. Either way, the binding
of the name to the object happens by evaluating to a "there" within the global dict object,
uniquely associated with the name ('x' here). Evaluated on the right hand side, that name will
produce the reference/pointer again for use in accessing the object or copying to another "there"
associated with perhaps some other name or a target within a composite object like a list or tuple,
or other namespace dict.

>
>The wart remains, even if my description was wrong. And even that is a
>dubious claim.
>

Every assignment is effectively stores a referential alias for an object,
whether associated with a name or not. This is by design, not a wart.

>A Python user is interested in how an object behaves - not how it is
>internally implemented in the interpreter. Immutable objects don't

when you say "immutable objects," are you really speaking of names
bound to immutable objects? I.e., the integer 123 is an immutable object
represented by the literal 123. You get an immutable object of the same value
from the expression int('123'). These are the int *objects* -- how does
"behave as references" apply to these actual "immutable objects"?
I.e., could you rewrite your sentence (that this is breaking in two)
to make it perhaps more understandable for me ?;-)

Names are not objects. Nor are left-hand-side assignment target expressions
in general, whether bare names or complicated.

ISTM what you are discussing is not about objects but about the way names work,
and ISTM you are thinking of names as if they were C++ variable references,
which they are not, and they couldn't be. For one thing, a C++ reference type
has to be initialized once to refer to a specific object. It can't be made to
refer to something else during the life of that scope. Pointers are a better
model, since you have to distinguish by expression syntax whether you mean
to assign a new pointer value or modify the thing pointed to. In python you
can only assign pointers, if you want to think in those terms. When you
modify a mutable, you are still assigning pointers into some part of the
mutable object representation. When you assign to a bare name, you are still assigning
a pointer into a place in some dictionary object (or workalike). If you
want to modify an object in the usual C sense, you can code it in C and provide a
python interface to your C-implemented object. When you pass arguments
to the various methods of your mutable, you will get pointers that you
can dereference and you can do what you want to your mutable's C data representation.
But when you pass the result back to the python world, it will have to be
as a standard object reference/pointer, and if you assign that, you will be
storing a pointer somewhere.

>behave as references - the internal use of references for immutable
>objects is basically a lazy copying optimisation and, apart from
>performace and a couple of other technicalities (e.g. the 'is'
>operator), has no relevance. Certainly it has no relevance to the
>point I was making.
>

The way it works is part of the semantics of the language, not just
an optimization issue.

Names aren't variables.

HTH ;-)

<disclaimer>I sometimes get things wrong. Corrections welcome.</disclaimer>

Regards,
Bengt Richter

Stephen Horne

unread,
Jul 13, 2003, 7:37:15 PM7/13/03
to

Java has the same problem as Python in this respect. You can either
state that it implements a different assignment semantic for some data
types than it does for other data types, or you can claim that some
data types have implicit built in references while others don't.

The Java rationale is essentially that 'pointer' is considered a dirty
word, so it was considered necessary to disguise them in Java. End
result - you have to use things which are not pointers as if they
were. You have to abuse data types in an arbitrary, confusing and
error-prone way in order to create the effect of pointers/references.

In Python, Guido describes his rationale for the existence of both
mutable lists and immutable tuples here...

http://www.python.org/search/hypermail/python-1992/0292.html

According to this, the benefit from an immutable tuple is that there
is no immediate copy, yet the tuples stored in the object are
protected from accidental 'mutation'. It allows a lazy copy-on-write
optimisation combined with preventing unwanted mutation of those
tuples. ie Guido justifies the need for an immutable tuple in terms of
copying - the rationale is about assignment, even though the effect is
the same as in Java in which the rationale is about disguising
pointers.

Note that Guidos rationale assumes a tie between the concepts of
'reference to value' and 'in place modifiability of part or all of
value'. This is bogus - these are two different concepts. There is no
reason why mutable objects shouldn't be assigned using copy-on-write
semantics, and there is no reason why there shouldn't be a simple
reference or pointer data type which has the explicit purpose of
providing indirect reference to single values of any type whether
mutable or immutable.

The only 'trouble' is that it suggests a need to distinguish
assignment to a variable (replacing the previous value even if it was
a pointer) from assignment to a pointed-to location. In fact you
already do this if you fake pointer functionality using mutable
objects, the only difference is that a pointer dereference is specific
to the real purpose and does not require abuse of data types that are
designed for other jobs.

People may say that pointers are bad news, but that impression
resulted from languages like C and Pascal and it should be qualified
in two ways. Pointers in C and C++ are dangerous in a very important
way. Pointers don't always point to a valid object - they may point to
something that was deleted, for instance. This is worse in the C
family as pointers and arrays are almost treated as the same thing,
and array subscripting has no bounds checking. Furthermore, there is
the risk of memory leaks.

If pointers always point to a valid object (except, perhaps, a special
pointer-to-none value which throws an exception on dereferencing), if
pointers are kept distinct from other abstractions such as arrays, and
there is no possibility of accessing whatever memory happens to be
beyond the bounds of some particular type, and if garbage collection
is used then the only reliability objections that can be levelled at
pointers would relate to code complexity - and that complexity can
only be increased by faking pointers using mutable types designed for
other tasks. All of these are perfectly plausible for a scripting
language.

Donn Cave

unread,
Jul 13, 2003, 8:30:20 PM7/13/03
to
Quoth Stephen Horne <intent...@blank.co.uk>:
...

| One way or the other, Python is currently choosing not to respect the
| computer science definition of those terms. It may have historic and
| backward-compatability reasons, but that does not change the facts.
| This deviation from computer science definitions, whatever the excuse,
| is arbitrary, confusing and error prone. That is my problem.

Well, there you have it - it does seem to be your problem. If we
were talking about a practical problem, we might be able to resolve
it with a few lines of code or an explanation of what really happens
when the code in question runs. But in this case, we all seem to
know perfectly well what happens, and how to write the code we need.

Python's system works. It's simple, practical and reasonably elegant.
If it doesn't work for you for some practical reason, I'd be surprised.
If you object to it on principle for some reason related to computer
science definitions, that really is your problem. I do suspect that
it would be also be due to some confusion on your part about either
how Python actually works, or what these computer science definitions
really say and how consistent and unambiguous they are, but from prior
experience with this type of thing I think it would be a mistake to
try to pursue it further here. It's computer science's job to describe
how Python works, not Python's job to match up with their terminology.
If you're one of those computer scientists, (or if you're not) you're
welcome to offer your interpretation.

Donn Cave, do...@drizzle.com

Fredrik Lundh

unread,
Jul 13, 2003, 8:00:07 PM7/13/03
to
Stephen Horne wrote:

> Java has the same problem as Python in this respect. You can either
> state that it implements a different assignment semantic for some data
> types than it does for other data types, or you can claim that some
> data types have implicit built in references while others don't.

Or you can explain how it actually works, instead of making things up as
you post. In my experience, most people prefer that approach.

</F>


David Abrahams

unread,
Jul 13, 2003, 9:02:49 PM7/13/03
to
Erik Max Francis <m...@alcyone.com> writes:

> This is completely incorrect. On the contrary, builtin types are
> handled exactly uniformly in Python. The only difference here is that
> the builtin types that you've listed, along with some others, are
> immutable, so you cannot change them if you have a reference to them.

All you guys must be forgetting:

>>> a = [1]
>>> b = a

>>> a += b
>>> assert id(a) == id(b)


>>> a = 1
>>> b = a

>>> a += b
>>> assert id(a) == id(b)
Traceback...

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Aahz

unread,
Jul 13, 2003, 9:30:54 PM7/13/03
to
In article <lq-cnWRG9rR...@comcast.com>,

Terry Reedy <tjr...@udel.edu> wrote:
>
>In Python, most builtin types are immutable. The two mutable builtin
>types are lists and dicts. Instances of user-defined classes are also
>mutable by default.

Actually, files are mutable, too. Then again, so are modules. And
functions. Gee, there are an awful lot of built-in mutable types. ;-)

Aahz

unread,
Jul 13, 2003, 9:32:37 PM7/13/03
to
In article <mailman.105812672...@python.org>,

Ian Bicking <ia...@colorstudy.com> wrote:
>
>(Admittedly, some confusion may occur because these very different
>operations use the same syntax:
>
> x = 10
> x[0] = 10
> obj.x = 10
>
>The second and third are entirely different from the first.)

No, they aren't. They are precisely the same; they just have different
assignment targets.

Roy Smith

unread,
Jul 13, 2003, 9:36:14 PM7/13/03
to
Jack Diederich <ja...@performancedrivers.com> wrote:
> I was a long time C++ guy and my a-ha moment was when I realized that the
> GoF's "Design Patterns" were not all universal -- some are C++ specific.
> Trying to force Python semantics into a C++ world view will leave you feeling
> empty every time.

Thank you for writing this, it makes me feel better!

I was having exactly this discussion just a couple of days ago with our
local hard-core C++ guy (who also poo-poo's Python, even though he's
never actually tried it). I made exactly the point Jack made -- that
the Design Pattern book is rather C++-centric, and some of it just
doesn't tranlate into Python very well.

For example, in the chapter on the Singleton pattern, a lot of time is
devoted to (what I consider) esoterica in the C++ access control system
(making copy constructors private, and all that stuff) to make sure
nobody can cheat and find a way to make a copy of the singleton. None
of that makes any sense in Python because (for better or worse), the
concept of private members just doesn't exist.

Aahz

unread,
Jul 13, 2003, 9:36:57 PM7/13/03
to
In article <mpn3hvkbd9sesm30d...@4ax.com>,

Stephen Horne <intent...@blank.co.uk> wrote:
>
>In Python, Guido describes his rationale for the existence of both
>mutable lists and immutable tuples here...
>
>http://www.python.org/search/hypermail/python-1992/0292.html

I'll note that Guido himself has also admitted that his ability to
explain his design decisions is far worse than his ability to select a
correct decision. These days, the rationale for tuples is that they're
a hyper-lightweight collection of heterogeneous values.

Aahz

unread,
Jul 13, 2003, 9:40:32 PM7/13/03
to
In article <usmp9q...@boost-consulting.com>,

David Abrahams <da...@boost-consulting.com> wrote:
>Erik Max Francis <m...@alcyone.com> writes:
>>
>> This is completely incorrect. On the contrary, builtin types are
>> handled exactly uniformly in Python. The only difference here is that
>> the builtin types that you've listed, along with some others, are
>> immutable, so you cannot change them if you have a reference to them.
>
>All you guys must be forgetting:
>
> >>> a = [1]
> >>> b = a
> >>> a += b
> >>> assert id(a) == id(b)
> >>> a = 1
> >>> b = a
> >>> a += b
> >>> assert id(a) == id(b)
> Traceback...

I'm not forgetting that. It's an unfortunate and tricky part of Python
semantics in some respects, but it's easily explained and understood if
you focus on the objects rather than the operation:

a = foo
b = a
a = a.__iadd__(b)

Where id(a)==id(b) depends solely on the behavior of __iadd__().

Aahz

unread,
Jul 13, 2003, 9:43:41 PM7/13/03
to
In article <sag3hv4vf884ed7ou...@4ax.com>,

Stephen Horne <intent...@blank.co.uk> wrote:
>
>In computer science, a variable is a named binding to a value.
>Operations on that variable may rebind it to a different value, but
>values don't change behind your back. A pointer is, in effect, a value
>which indirectly refers to another (possibly anonymous) variable. A
>pointer is something you specifically request, and by doing so you
>allow that the 'variable' being indirectly referenced may be modified
>by something else that has no direct access to your pointer value (via
>your named variable or via copys or pointers-to your pointer held
>elsewhere).
>
>Python should respect that.

That's why I (and others) prefer to use "name" and "target" instead of
"variable". Would that assuage your ire?

Ian Bicking

unread,
Jul 13, 2003, 9:18:25 PM7/13/03
to
I don't know why I'm participating, but it's feels hard to stay out of
this one...

On Sun, 2003-07-13 at 17:17, Martin v. Löwis wrote


> > 3. Why is there no way to reference an immutable object via a
> > pointer, other than stuffing it into a mutable object designed for
> > some purpose other than simple pointer behaviour?
>
> But there is: If I do
>
> a = 1
> b = a
>
> then b *refers* the same value that a refers to. That is, the values
> associated with a and b have the same identity.

I think, then, that Stephen maybe wants to do something like:

>>> a = ref(1)
>>> b = a
>>> b is a
True
>>> a + 2
3
>>> a = 5
>>> b
5

And so on. This is all quite doable in Python (implementation of ref
left to the reader), except for the "a = 5" part. Instead you'd have to
do something like "a.set(5)". Even though it is doable, of course, it's
by way of clever hacks.

The problem that Stephen is not appreciating is that this sort of
reference implies that "a" is a typed variable -- of type "pointer",
somehow implicitly declared when it was initially assigned a ref
object. (He's not alone, because just a little while ago someone
proposed a way to overload the meaning of "=", to achieve largely the
same functionality)

It might not be quite as ugly-seeming if we explicitly declared "a" as a
pointer. Besides the disinclination of people to add variable
declarations (though "global" already is one), it's more difficult
because there's now a new type that has to be usable everywhere, the
pointer type. All Python's code that expected, say, integers would have
to also be ready to dereference the argument and then use it. It could
probably be made seamless at the Python level fairly easily, but the C
would be annoying, no doubt.

One might think you could just use the references that already exists
(since variables are references, and everything is passed by
reference). But that's messed up, because that'd mean:

>>> b = 2
>>> pointer a
>>> a = 2
>>> a is b
True
>>> a = 5
>>> b
5

The ability to redefine the integers is obviously not a good feature
(though I remember someone saying you can accidentally do some stuff
like this in C extensions).

Anyway, that's my attempt at empathy with Stephen, if not agreement. If
he is wanting something other than what I've described, he should give
other examples, because code examples are better than words.

Ian

Stephen Horne

unread,
Jul 13, 2003, 10:24:28 PM7/13/03
to

Appols for changing the subject while still staying in the same topic
- I just wanted to highlight this over my earlier boneheaded posts.

This is a post of heavily qualified appologies. In summary, I've been
thick-headed but I still believe that Python is doing the wrong thing.

I hope I've actually achieved a degree of sanity on this attempt ;-)


On 14 Jul 2003 00:17:19 +0200, mar...@v.loewis.de (Martin v. Löwis)
wrote:

>Stephen Horne <intent...@blank.co.uk> writes:
>
>> 1. Why are dictionarys called dictionaries (rather than references to
>> dictionarys or whatever)? Similar for lists and class instances.
>
>Because they are the values themselves, instead of being references to
>values. These values (like all other values) are objects, though,
>which means they have identity, state, and behaviour.

I've said my piece on meanings derived from computer science (and in
turn from mathematics, as it happens - variables as placeholders for
values predate electronic computers by quite some time.

People have tried to point out that copy-on-write is redundant for
immutable objects, but I've been too thick-headed. Sorry for that.

Even so, you can think of immutable objects as achieving 'expected'
assignment semantics simply because they are immutable. That does not
apply to mutable objects. So you can claim that Python behaviour is
consistent within itself, but only by claiming that it is consistently
different from this 'expected' behaviour.

Some people have already said that the word 'expected' is a fallacy -
that computer science doesn't have fixed definitions for these things.
Some have already named various languages which deviate in similar
ways in either some or all cases. But these languages are actually
deviating, either by convention or (in older cases) due to the
limitations of past machines. That's not the same thing as saying they
are doing 'the right thing' or that the computer science definitions
don't exist - all it means is that a lot of programmers who are
experienced in certain languages are familiar with this error-prone
system and used to compensating for its problems. But a modern
high-level language should do 'the right thing' - it should not be the
programmers job to make allowances for an outdated workaround designed
to give maximum performance by default on old machines irrespective of
reliability.

>> 2. Why are the values of mutable objects always forced to be accessed
>> via a pointer (or reference or whatever)?
>
>Because all variables are references to objects.

All variables are implemented as references, but that is not the same
as saying that all values are references. As Guidos own words reveal
(I already posted the link twice) the purpose of using immutables
tuples is performance optimisation to save copying while still
defending against against accidental mutation (ie it provides the
computer theory standard assignment semantics efficiently).

The same rationale should equally apply to all types, including the
mutable types.

In particular, it should apply to class instances. I shouldn't need to
create separate mutable and immutable variants of classes to get this
as the mutability of content should be the decision of the container
rather than the content. I shouldn't need to force copying of class
instances in the container for the exact same reason that Guido
highlights for tuples.

Guidos own example is actually quite bug prone in its own way. It
behaves differently depending on whether you pass in the point values
as tuples or lists. That is potentially a subtle, intermittent,
hard-to-trace error waiting to happen. You can say 'validation' all
you want. I did that back in the PEP238 days, and didn't get much
support. What's good for the goose is good for the gander.

>> This excuse is, as I already said, invalid.
>
>Which excuse? You have only listed questions in this message, not
>excuses.

Looking back, I was unfair to Tim Peters. The 'excuse' was percieved
(mainly because I'm frustrated trying to get my point across, and
because a circularity that arose (unless I was thick-headed about that
too) in another post. I said 'if a then b', someone said 'no - a is
wrong because c', I said 'ah, but if c then d' and the reply to that
was 'no - c is wrong because a' - or at least I think that's what
happened. Possibly I just need some sleep.

I thought Tim was also guilty of this, but looking back I was wrong.
Sorry, Tim.

However, revisiting his post I still disagree with it...

"""
It's deliberate and thoroughly consistent. Any assignment semantics
are
error-prone in some contexts, though (Python's included -- side
effects are
like that). The simplicity and absolute consistency of Python-style
assignment semantics are probably easiest for first-time programmers
to pick
up, and certainly dead easy for people coming from Lisp (etc) to pick
up --
people coming from C (etc) often struggle with inappropriate
expectations at
first.
"""

At first glance it looked like Tim was saying 'its all assignment
semantics rather than type semantics', hence my misjudging him. But
one way or the other, there is an inconsistency between the behaviour
of mutable objects and the computer science definitions of 'variable',
'value' and 'assignment' which does not arise for immutable objects
(note careful wording - see earlier apology). Having copy-on-write for
all objects (obviously the actual copying never happening for
immutables) would be both fully self-consistent and consistent with
the computer science definitions. The lack of this definitely does
cause both confusion and errors.

I also disagree with Tims statement that "Any assignment semantics are
error-prone in some contexts". OK, mistakes can be made with any
syntax for anything, but in the context of this discussion it is
perfectly possible to get the best of both worlds.

Make pointers/references explicit and make all assignments
'copy-on-write', and as I said earlier you get both mutability
protection by default for all types and the ability to reference any
type indirectly. Avoid the problems that make pointers in C, C++,
Pascal etc so unreliable and, while perceptions of pointers as being
inherently bug prone may persist they would be irrational - having
pointers explicitly for all types would at worst be as bug prone as
the existing situation where implicit references exist, and in
particular where mutable types get abused to fake pointer/reference
capabilities. It needs extra notation, but when mutables are used to
fake pointers there is extra notation anyway - misleading notation.

I'm not an anti-side-effect fanatic. I just don't want them to happen
by default, and I don't have to worry about this every time I use a
mutable type. And there really is no need for that to happen.

Stephen Horne

unread,
Jul 13, 2003, 10:35:18 PM7/13/03
to
On Sun, 13 Jul 2003 21:36:14 -0400, Roy Smith <r...@panix.com> wrote:

>Jack Diederich <ja...@performancedrivers.com> wrote:
>> I was a long time C++ guy and my a-ha moment was when I realized that the
>> GoF's "Design Patterns" were not all universal -- some are C++ specific.
>> Trying to force Python semantics into a C++ world view will leave you feeling
>> empty every time.
>
>Thank you for writing this, it makes me feel better!
>
>I was having exactly this discussion just a couple of days ago with our
>local hard-core C++ guy (who also poo-poo's Python, even though he's
>never actually tried it). I made exactly the point Jack made -- that
>the Design Pattern book is rather C++-centric, and some of it just
>doesn't tranlate into Python very well.

I thought that book uses Java (and UML)?

I agree with the point, though. A pattern is supposed to be a standard
way to implement an abstraction, but the best way to implement some
abstraction varies from language to language.

Stephen Horne

unread,
Jul 13, 2003, 10:39:34 PM7/13/03
to
On 13 Jul 2003 21:30:54 -0400, aa...@pythoncraft.com (Aahz) wrote:

>In article <lq-cnWRG9rR...@comcast.com>,
>Terry Reedy <tjr...@udel.edu> wrote:
>>
>>In Python, most builtin types are immutable. The two mutable builtin
>>types are lists and dicts. Instances of user-defined classes are also
>>mutable by default.
>
>Actually, files are mutable, too. Then again, so are modules. And
>functions. Gee, there are an awful lot of built-in mutable types. ;-)

True. Damn. 'Boneheaded' is definitely my thing, today.

Stephen Horne

unread,
Jul 13, 2003, 10:41:46 PM7/13/03
to
On 13 Jul 2003 21:40:32 -0400, aa...@pythoncraft.com (Aahz) wrote:

>In article <usmp9q...@boost-consulting.com>,

>>All you guys must be forgetting:
>>
>> >>> a = [1]
>> >>> b = a
>> >>> a += b
>> >>> assert id(a) == id(b)
>> >>> a = 1
>> >>> b = a
>> >>> a += b
>> >>> assert id(a) == id(b)
>> Traceback...
>
>I'm not forgetting that. It's an unfortunate and tricky part of Python
>semantics in some respects, but it's easily explained and understood if
>you focus on the objects rather than the operation:

I wish I'd thought of it, though - I could have avoided the
'boneheaded' confession a bit longer ;-)

Ian Bicking

unread,
Jul 13, 2003, 10:47:30 PM7/13/03
to
On Sun, 2003-07-13 at 20:32, Aahz wrote:
> In article <mailman.105812672...@python.org>,
> Ian Bicking <ia...@colorstudy.com> wrote:
> >
> >(Admittedly, some confusion may occur because these very different
> >operations use the same syntax:
> >
> > x = 10
> > x[0] = 10
> > obj.x = 10
> >
> >The second and third are entirely different from the first.)
>
> No, they aren't. They are precisely the same; they just have different
> assignment targets.

Sure they are different. The first is a primitive operation binding the
variable x. The second gets x, and calls x.__setitem__(0, 10), and the
third is equivalent to setattr(obj, 'x', 10).

The first is primitive syntax. I suppose you could say that it could be
reduced to operations on locals() and globals(), but I feel like that's
a detail that is best not brought up ;) The local and global scope are
not as flexible as other objects The other two are really just syntactic
sugar.

Ian

Donn Cave

unread,
Jul 13, 2003, 11:40:05 PM7/13/03
to
On Sun, 2003-07-13 at 20:32, Aahz wrote:
> In article <mailman.105812672...@python.org>,
|> Ian Bicking <ia...@colorstudy.com> wrote:
|>>
|>> (Admittedly, some confusion may occur because these very different
|>> operations use the same syntax:
|>>
|>> x = 10
|>> x[0] = 10
|>> obj.x = 10
|>>
|>> The second and third are entirely different from the first.)
|>
|> No, they aren't. They are precisely the same; they just have different
|> assignment targets.
|
| Sure they are different. The first is a primitive operation binding the
| variable x. The second gets x, and calls x.__setitem__(0, 10), and the
| third is equivalent to setattr(obj, 'x', 10).

I wonder if this is a good example of a mutability thing that really
is kind of missing to the detriment of Python.

If you want to support user-implemented sequences (as Python does)
but make Aahz's ``precisely the same'' assertion true in the sense
you're taking it - then I think the user-implemented indexing function
would have to return a reference to the index location.

class UserArray:
...
def __item__(self, index):
return &self.internal_array[index]

userArray[5] = 1
(python internal)
loc = UserArray.__item__(userArray, 5)
*loc = 1

if userArray[6] ==
(python internal)
loc = UserArray.__item__(userArray, 6)
return *loc

There are other places where instead we use some kludge with a
mutable container type, but in this case I don't think there's
a way to get around it. So whether we like the idea or not,
assignment to a user-implemented sequence doesn't have to involve
any assignment at all, because Python lacks the "pointer" type
(or "target" type, if you prefer) that would be required to
implement that.

Donn Cave, do...@drizzle.com

Stephen Horne

unread,
Jul 13, 2003, 11:43:07 PM7/13/03