[Python-Dev] behavior of inplace operations
Guido van Rossum
guido@python.org
Wed, 12 Jun 2002 11:13:26 -0400
> > One problem is that it's really hard to design the bytecode so that
> > this can be implemented. The problem is that the compiler sees this:
> >
> > a[i] += x
> >
> > and must compile bytecode that works for all cases: a can be mutable
> > or immutable, and += could return the same or a different object as
> > a[i]. It currently generates code that uses a STORE_SUBSCR opcode
> > (store into a[i]) with the saved value of the object and index used
> > for the BINARY_SUBSCR (load from a[i]) opcode. It would have to
> > generate additional code to (a) save the object retrieved from a[i]
>
> Isn't that already lying about on the stack somewhere? Didn't you have to
> have it in order to invoke "+= x" on it? (I'm totally ignorant of Python's
> bytecode, I'll be the first to admit)
Getting that object is the easy part.
> > (b) compare the result to it using the 'is' operator, and (c) pop some
> > stuff of the stack and skip over the assignment if true. That could
> > be done, but the extra test would definitely slow things down.
>
> As was suggested by someone else in the thread I referenced, I was thinking
> that a new bytecode would be used to handle this. It has to be faster to do
> one test in 'C' code than it is to re-indexing into a map or even to do the
> refcount-twiddling that goes with an unneeded store into a list.
>
> > A worse problem is that it's a semantic change. For example,
> > persistent objects in Zope require (under certain circumstances) that
> > if you modify an object that lives in a persistent container, you have
> > to store it back into the container in order for the persistency
> > mechanism to pick up on the change. Currently we can rely on a[i]+=x
> > and a.foo+=x to do the assigment. Under your proposal, we couldn't
> > (unless we knew that the item was of an immutable type).
>
> That's right. I would have suggested that for persistent containers, the
> object returned carries its own write-back knowledge.
But that's not how it works. Giving each container a persistent
object ID is not an option.
> > That is such
> > a subtle change in semantics that I don't want to risk it without
> > years of transitional warnings.
>
> Hah, code breakage. The purity of the language must not be compromised, at
> any cost! Well, ok, if someone's actually using this extra step I guess you
> can't change it on a whim...
>
> > Personally, I'd rather accept that if you have a = ([], [], []),
> > a[1]+=[2] won't work. You can always write a[1].extend([2]).
>
> It's your choice, of course. However, it seems a little strange to have
> this fundamental operation which is optimized for persistent containers but
> doesn't work right -- and (I assert without evidence) must be slower than
> neccessary -- in some simple cases. The pathological/non-generic cases are
> the ones that make me think twice about using the inplace ops at all. They
> don't, in fact, "just work", so I have to think carefully about what's
> happening to avoid getting myself in trouble.
You have a habit of thinking too much instead of using common
sense. :-)
--Guido van Rossum (home page: http://www.python.org/~guido/)