Patch references to auto-persistent objects in a module.
When a persistent module is compiled, all classes and functions should be converted to persistent classes and functions. When a module is updated, it is compiled and its persistent functions and classes are updated in place so that clients of the module see the update.
The specific semantics of the convert and update-in-place operations are still being determined. Here are some rough notes:
Implementation notes --------------------
The conversion operation is implemented using a pickler. It wasn't possible to use the copy module, because it isn't possible to extend the copy module in a safe way. The copy module depends on module globals.
The pickler uses a Wrapper object that creates the appropriate new object or updates an old one when it is unpickled. The wrapper also causes parts of the wrapped object's state to be traversed by the pickler, for example the func_defaults of a function object. This traversal is necessary because references to convertable objects could be contained in the state and must be updated to refer to the new objects.
What semantics do we want for update-in-place in the presence of aliases?
Semantics based on per-namespace updates don't work in the presence of aliases. If an update changes an alias, then the old binding will be updated with the state of the new binding.
Semantics based on containing namespaces seem to work. The outermost namespace that contains a name is updated in place. Aliases are simple rebinding operations that do not update in place.
The containment approach seems to have a problem with bound methods, where an instance can stash a copy of a bound method created via an alias. When the class is updated, the alias changes, but the bound method isn't. Then the bound method can invoke an old method on a new object, which may not be legal. It might sufficient to outlaw this case.
Open issues -----------
Can we handle metaclasses within this framework? That is, what if an object's type is not type, but a subclass of type.
How do we handle things like staticmethods? We'd like the code to be able to use them, but Python doesn't expose an introspection on them.
What if the same object is bound to two different names in the same namespace? For example:
x = lambda: 1 y = x
If the module is updated to:
x = lambda: 1 y = lambda: 2
What are the desired semantics?