[Python-Dev] PEP 351, the freeze protocol
jcarlson at uci.edu
Sun Oct 30 02:34:12 CEST 2005
Noam Raphael <noamraph at gmail.com> wrote:
> I have thought about freezing for some time, and I think that it is a
> fundamental need - the need to know, sometimes, that objects aren't
> going to change.
I agree with this point.
> This is mostly the need of containers. dicts need to know that the
> objects that are used as keys aren't going to change, because if they
> change, their hash value changes, and you end up with a data structure
> in an inconsistent state. This is the need of sets too, and of heaps,
> and binary trees, and so on.
You are exactly mirroring the sentiments of the PEP.
> I want to give another example: I and my colleges designed something
> which can be described as an "electronic spreadsheet in Python". We
> called it a "table". The values in the table are Python objects, and
> the functions which relate them are written in Python. Then comes the
> problem: the user has, of course, access to the objects stored in the
> table. What would happen if he changes them? The answer is that the
> table would be in an inconsistent state, since something which should
> be the return value of a function is now something else, and there's
> no way for the table to know about that.
I respectfully disagree with this point and the rest of your email. Why?
For two use-cases, you offer 'tables of values' and 'graphs', as well as
a possible solution to the 'problem'; copy on write.
In reading your description of a 'table of values', I can't help but be
reminded of the wxPython (and wxWidget) wx.Grid and its semantics. It
offers arbitrary tables of values (whose editors and viewers you can
change at will), which offers a mechanism by which you can "listen" to
changes that occur to the contents of a cell. I can't help but think
that if you offered a protocol by which a user can signal that a cell
has been changed, perhaps by writing the value to the table itself
(table.SetValue(row, col, value)), every read a deepcopy (or a PEP 351
freeze), etc., that both you and the users of your table would be much
As for the graph issue, you've got a bigger problem than users just
being able to edit edge lists, users can clear the entire dictionary of
vertices (outgoing.clear()). It seems to me that a more reasonable
method to handle this particular case is to tell your users "don't
modify the dictionaries or the edge lists", and/or store your edge lists
as tuples instead of lists or dictionaries, and/or use an immutable
dictionary (as offered by Barry in the PEP).
There's also this little issue of "copy on write" semantics with Python.
Anyone who tells you that "copy on write" is easy, is probably hanging
out with the same kind of people who say that "threading is easy". Of
course both are easy if you limit your uses to some small subset of
interesting interactions, but "copy on write" gets far harder when you
start thinking of dictionaries, lists, StringIOs, arrays, and all the
possible user-defined classes, which may be mutated beyond obj[key] =
value and/or obj.attr = value (some have obj.method() which mutates the
object). As such, offering a callback mechanism similar to weak
references is probably pretty close to impossible with CPython.
One of the reasons why I liked the freeze protocol is that it offered a
simple mechanism by which Python could easily offer support, for both
new and old objects alike. Want an example? Here's the implementation
for array freezing: tuple(a). What about lists? tuple(map(freeze, lst))
Freezing may not ultimately be the right solution for everything, but it
is a simple solution which handles the majority of cases. Copy on write
in Python, on the other hand, is significantly harder to implement,
support, and is probably not the right solution for many problems.
P.S. To reiterate to Barry: map freeze to the contents of containers,
otherwise the object can still be modified, and hence is not frozen.
More information about the Python-Dev