I think Huaiyu Zhu and I are thinking along very similar lines.
> Yes. Very insightful. It is easy to fall into this line of
> thinking and not see the the traps. I was heasitent when
> I put in the "base class" stuff in the update to the PEP
> being promoted.... it just seemed expected. Perhaps it
> isn't the right thing to do. Once you have classes,
> people like to treat class inheritance as interface
> inheritance...
>> The rest of your post resonates deeply. Is there some
> way to get a "simple" __query__ mechanism working
> without having the type system in place?
I think the major trap would be going with a system which did not have
sufficient expressiveness. One of the problems with passing a base class
object (or class instance) to __adapt__() is that there is no standard way
to specify requirements other than "interface has these methods".
In interface descriptor class is much more general, and much more easily
extended. For example, the first iteration could simply be used to add
method requirements. Then we could add method parameter and return type
signatures. Then pre- and post- conditions (such as parameter #3 <= 5). And
so on.
Huaiyu (I hope that's your given name - can't always tell with other
cultures whether the family name is first or last ;) appears to have gone
some way with what I envisage, but not all the way. I am so tempted to just
drop what I'm working on and get into this ...
An interface descriptor class itself would have to meet the interface
requirements for interface descriptors or it would be rejected by the
builtin adapt() function ;) I would actually propose a builtin "interface"
base class which contains all the required functionality from which specific
interface descriptor classes could be subclassed and/or instantiated. Note
that this would be a backwards-compatible change - it is simply adding a
name to the last namespace searched - likewise with the adapt() builtin
function.
I think the adapt stuff would work as follows (incomplete - doesn't really
do anything). Note: while working on this I discovered that both an
__adapt__() and __query__() method would be useful ... the __query__()
method could be used by a class to verify that it meets a single
requirement. Second note: This was coded up in about 15 minutes so there are
likely flaws.
class __requirement:
""""""
def __init__(self):
""""""
def verify (self, adaptor, __query__=None):
""""""
# Allowed to pass in query to speed things up.
# If so, it *must* be the adaptor.__query__() method
if not __query__:
query = getattr(adaptor, '__query__', None)
# The __query__() method can return one of 3 types of
# values.
#
# True (e.g. 1): The object *definitely* does
# implement this requirement and should not be
# checked further
#
# False (e.g. 0): The object *definitely* does
not
# implement this requirement and should not be
# checked further
#
# None: The __query__() method doesn't know if
it
# implements this requirement and its
attributes
# should be checked to see if it does or not.
if __query__:
query = adaptor.__query__(self)
if query:
return adaptor
elif query != None:
return None
# For now, we will just verify that the object has the
# named attribute. Later this can be more complex
# (parameters, signatures, etc)
attr = getattr(adaptor, self.getName(), None)
if attr:
return adaptor
# Not required, but explicit is better than implicit
;)
return None
class interface:
""""""
def __init__(self):
""""""
def requirements (self):
""""""
# return sequence of __requirement - requirements are
# generated automatically by factory methods in the
# interface class
return ()
def __adapt__(self, descriptor):
""""""
# For now, only interface and its subclasses will be
# directly adapted. Later we will add a verification
# process directly here as the requirements() method
# should return an empty sequence unless requirements
# have been added by subclasses or instances
if self == descriptor or isinstance(descriptor, interface):
return self
__interface = interface()
class implements:
""""""
def __init__(self):
""""""
def __query__(self, requirement):
""""""
def adapt(descriptor, object):
# Verify that the interface object actually meets
# the requirements for the interface descriptor interface
if interface:
assert adapt(None, descriptor)
else:
descriptor = __interface
adapted = None
__adapt__ = getattr(object, '__adapt__', None)
if __adapt__:
adapted = object.__adapt__(descriptor)
if not adapted:
adapted = object
__query__ = getattr(object, '__query__', None)
for r in descriptor.requirements():
if not r.verify(adaptor, __query__):
adapted = None
break
if adapted:
return adapted
else:
raise AttributeError('Does not implement interface')
if __name__ == '__main__':
print adapt(interface(), implements())