[TransWarp] PROPOSAL: Get rid of binding.AutoCreated/AutoCreatable
Phillip J. Eby
pje at telecommunity.com
Wed Nov 27 19:47:17 EST 2002
(Interestingly, after I wrote the first couple of paragraphs of this
proposal, I found out that our implementation of 'AutoCreated' (really in
'OnceClass') can cause Python 2.2.x to dump core, because of a 2.2.x
bug. But that's *not* the reason for this proposal, since we could work
around the Python bug if we so chose. This proposal is intended to remove
what I believe are now-superfluous and overly "magical" features in
'peak.binding'.)
When you subclass binding.AutoCreated, you get a class that, when placed
inside another class definition, will create an instance of the AutoCreated
subclass upon retrieval. It is, in effect, as though you had a
binding.New() wrapped around the nested class.
Nested classes, however, are not considered by the BDFL to be good Python
style in situations where the contained class is merely a "helper" of the
outer class.
Worse, there is no way you can actually have a class-defined instance
attribute which is an AutoCreated subclass. If you do this, you'll get a
fresh instance of the class instead.
It seems to me that this violates the principle of "explicit is better than
implicit", since it is not possible to tell what a nested class is going to
actually do, without first inspecting the source code of all its base
classes to find out if they subclass AutoCreated!
What I propose, then, is to simply get rid of binding.AutoCreated and its
supporting metaclass machinery (OnceClass and AutoCreatable). In places
where we currently use nested classes to define autocreateds, we will add a
binding.New(), as follows::
# Before
class Thing(binding.Component):
class Nested(binding.AutoCreated):
...
# After
class Thing(binding.Component):
class Nested(binding.Component):
...
Nested = binding.New(Nested)
The net result is that such bindings are always explicit. This takes a
little more work to do, but will let us clean up some bits of cruft
associated with the AutoCreated classes and metaclasses.
There are a few possibly negative side effects. In the example above,
'Nested' is no longer accessible as a class, even as a class
attribute. This could be worked around by giving the class and attribute
binding different names, e.g. 'class _Nested' and 'Nested =
binding.New(_Nested)'. This would also be necessary for classes that you
wished to have treated as components in themselves, otherwise they will
consider their parent component to be the module, rather than the class
they are contained in.
But the most common use case for a nested class that is to be auto-created,
is when you want to build a structure of nested service components. In
this situation, the classes themselves aren't the components; their
instances are. There's really no point to accessing the classes, either,
unless you plan to pickle the structure. If you're pickling the structure,
then you'll need 'config.setupModule()' anyway, and it will still do its
normal class name mangling (e.g. '__name__ = "Thing.Nested";
globals()["Thing.Nested"] = Nested') when the class is created. So, I
don't really see a use case for *not* using 'binding.New()' to wrap a
nested class for creation, except to save some typing. :)
There are also some other advantages to being explicit. One can use a
different docstring for the binding than the class, for example, or specify
different 'provides' configuration keys.
Anyway, as of this point, I'd like to consider AutoCreated et al to be
"deprecated", and immediately begin standardizing PEAK not to use them any
more. (They also will NOT be documented in the tutorial.) If there are no
serious objections, I'd also like to go ahead and remove them from the code
base. If you're using them and can't change for some reason, please let me
know right away.
More information about the PEAK
mailing list