Yet Another PEP: Query Protocol Interface or __query__
Carlos Alberto Reis Ribeiro
cribeiro at mail.inet.com.br
Mon Mar 26 10:22:53 EST 2001
Clark,
The main point of my implementation was the idea of building the adapter
from a empty 'Protocol' class, adding to it methods that are bound to the
original object. This and a few helper functions solve the first part of
the problem (the object returning an adapter).
Please also note that I made a clear division between an 'object instance'
and a 'protocol instance'. The protocol instance, or adapter, is a proxy
object. It's implemented as a normal Python object, but all its methods are
redirected as described above. This approach has some advantages:
a) The proxy adapter is completely transparent to the object instance.
b) The adapter maps only the methods that are mandatory by the protocol
specification. This leads to better encapsulation and abstraction (all
details of the object are hidden from the protocol user).
c) Method names may be different in the object. The protocol does the name
translation.
d) The protocol instance may point to methods in disparate objects, which
leads to a interesting type of 'composition'.
Anyway, did you take a look at my example? Please disregard the explanation
of the protocols in terms of interfaces. The details can be changed without
changing the essence of the proposal.
Now some comments, in a different order from your original email; I moved
the two-way adapter discussion to the end of the message.
At 23:08 25/03/01 -0500, Clark C. Evans wrote:
>On Mon, 26 Mar 2001, Carlos Ribeiro wrote:
> > 1) What is a protocol? The simplest definition that I cant think of is: a
> > protocol is just a bunch of methods. An object is said to support a
> > protocol if it implements all methods of the protocol specification. The
> > specification defines the names and parameters of all methods.
>
>This is what an interface is, and there is a proposal
>for this. A protocol should be more broadly defined, no?
Hummm... I see your point. My intention is different - avoid mixing
'protocols' and 'class definitions'. One of the reasons was the potential
for name clashes, as shown in my example. A protocol does not need to be
represented *exclusively* by a class in the hierarchy. A single class may
implement multiple protocols, but some protocols may need a composition of
objects to do the work. For example, a composite object may contain lots of
objects that gets exposed through interfaces in the container.
Also I see no reason to avoid defining some kind of 'simple' interfaces in
this PEP - in the end, protocols are better mapped to 'interfaces' than to
'classes'. It's much more flexible in this way.
OTOH, it is possible to use 'protocol classes' instead of strings to
describe the protocol. The implementation does not change very much. The
catch here is to avoid the assumption that *implementing* a protocol is the
same as inheriting from the abstract protocol class. For example:
class ProtocolSequence:
""" Protocol to implement sequence-like objects """
def __len__ (self): pass
def __getitem__(self, key): pass
def __setitem__(self, key, value): pass
def __delitem__(self, key): pass
In this example, ProtocolSequence is the specification of the methods used
for sequence type objects. Sequence objects does not need to be derived
from ProtocolSequence; they may be written from the scratch, or be derived
from UserList, etc. Again, keep in mind the potential of composition as a
technique to build large systems. It is important to avoid the assumption
that inheritance is *the only way* to build OO systems.
MakeProtocol would then use some getattr/setattr 'magic' to build the
method list, and to 'rebind' all the methods to the ones in the object
being adapted. I'm not checking the method signatures though; this would
need some help from the compiler in order to work.
(note: MakeProtocol is not a good name. MakeAdapter, or
MakeProtocolInstance, is better)
>IMHO, the goal was to have this dialogue...
The implementation that I sent March 25 is one-way only. It is somewhat
simpler, because I dont need to define a separate protocol class - it's
just a matter of building the adapter inside the __adapt__ method. Also, I
did not see yours (Clark's) dialogue implemented in the last version of the
draft (I have read the one from March 21, did I miss something)?
TWO-WAY IMPLEMENTATION
For a two-way implementation, I suggest the following dialogue (about the
same as your):
Hello protocol manager, do you know if this
object X here supports the protocol Y?
The protocol manager then does:
Hello object X, do you support protocol Y?
Please return an adapter if so.
Object X says: yes, I do support Y, and here
is the adapter. Otherwise, X would have nothing
to give back to the protocol manager.
if the object doesn't know about protocol Y,
then the protocol itself is asked about X:
Protocol Y, do you know about object X?
Protocol Y says: Yes, I checked object X
class/methods/protocols, and I think that I
can make an adapter for you.
I initially had some concerns over the two-way implementation. The main
reason is that only an object could possible know how to adapt itself to a
given protocol. Now I see that this could be possible, specially if we
provide some helper functions to hide some hacks that Y would need to do in
order to check X structure. I see three things that could be checked by the
protocol:
a) class inheritance, as in your example. However it does limit 'protocol'
to 'root classes', and it does have a problem with multiple inheritance,
namely because of potential name clashes. It also does not work if the
object is built not by inheritance, but by *composition*.
b) methods, or 'interface signature'. In this case the protocol just checks
if the object does support all methods required by the protocol.
c) protocol compatibility. The protocol may ask the object directly for
some compatible protocol, and then built a new adapter. This could be done,
for instance, if you have a newer version of a protocol with only small
changes; the protocol itself provides the interoperability layer with the
previous version.
Some helper functions could be provided to help in these cases, for example:
def TestMethods(object, list_of_method_names):
""" check to see if object supports all methods
listed on the second parameter
"""
(...)
I'll try to build a new example with these points in mind.
Carlos Ribeiro
More information about the Python-list
mailing list