PEP 245

Alex Shindich shindich at itginc.com
Wed Apr 4 18:25:12 EDT 2001


Michel,
	Thank you for the explanations! Your reply did clear up some of the
concerns I had regarding this PEP.
I still have a few objections though:

>> 1. What is the point of interfaces without static typing?
>To assert a contract is one.  To separate various implementations of the
>same interface without them loosing a common usage is another.
>No mandatory enforcement is being proposed.
This means that interface support in Python will be limited to three
applications:
1. Clear documentation of the interfaces
2. Separation of inheritence hierarchy from the implementation hierarchy
3. An ability to dtermine if a particular object supports a specific
interface.
Am I missing anything out?

>> 2. At what point will the compliance with the interface definition be
>> done, at compile time, or at run time?
>There is no madatory compliance or interface enforcement proposed in 245.
>These things are optional, and they should be optional.  Turn on for
>unit-testing, debugging, etc, turn off for production and speed.
Great!

>> If the compliance is checked at run time, then interface checking is as
>> good as as simply assuming that the method is implemented. Today, I can
>> compile code like "f.doSomething ()" without f actually implementing
>> doSomething. At run time I would get an AttributeError thrown into my
>> face. In fact, the run time compliance is available already.
>
>Interfaces, strong or weak, are not going to solve any of these problems
>in a magic bullet fasion. There's a million ways around even strong
>interfaced languaged, even ones that go so far as to check pre and
>post-condition contract boundaries.
I was not trying to identify the problems. On the contrary, my point was
that run-time checking is supported today, i.e. if the method is not
present, an AttributeError exception will be thrown.
BTW. Are you planning on throwning an InterfaceError exception instead of
AttributeError?

>One of the major reasons for the PEP is to assert that an object can be
>used in a certain way, without caring about how it is implemented.  It's
>telling you something about what it can do, without you having to know the
>difference between the flat-file implementation and the one that uses a
>relational database.
>Currently this ability in Python is weak, and is based on looking at
>classes.  But classes are not meant to be explicit interfaces, they are
>ways of sharing implementaiton.
I see your point. But I think that proposed interface behavior is missing a
very important attribute -- an explicit facility for acquiring interface
references. Per you proposal, the reference to the object is
indistinguishable from the reference to the interface. In Java the reference
to the interface is obtained using a type cast, i.e.
	IProgrammer prg = (IProgrammer) obj;
In COM, the same is accomplished through the use of QueryInterface, i.e.
	IProgrammer * pIProgrammer = NULL;
	HRESULT hr = pIObj->QueryInterface (IID_IProgrammer,
reinterpret_cast<void**> (&pIProgrammer));
	if (SUCCEEDED (hr))
	...
	or
	CComQIPtr<IProgrammer, &IID_IProgrammer> tIProgrammer(pIObj);
	if (!tIProgrammer)
	...

There is no such thing proposed in PEP 245.
If the interfaces are added to Python, I would like to have a way of
distinguishing between references to the object and references to the
interface. In fact, I would like that to be more similar with COM rules
where class implmenetor is responsible for the implementation of
QueryInterface (although default behaviour should be provided). This permits
playing all sorts of identity tricks, such as component aggregation, and
tear-offs. How about adding __getinterfacereference__ that as name implies
returns the interface reference? I guess a built-in
	getinterface (object, interface) -> interface reference
would have to be added as well.

>No, Java interfaces are just compile time enforcement.  The syntax is
>vaguely similar.
But the concept is similar. Java interfaces assert a contract, and allow
documenting it. In Java one can find out if class implements an interface.
The syntax is extremely similar... Not that there is anything wrong with
Java syntax.

>Take me for example.  If I were a python object, I'd be an instance of a
>class that is generalized by two other classes, my mom and dad.  That's my
>type, my genetics.
class Dad:
	...
class Mom:
	...
class Son (Dad, Mom):
	...

>Now, let's say you were a function that expected a
>'Python programmer'.  You could wire that expectation to my implementation
>(my class), but then, I'd be the only "kind" of python programmer you could
>use.  You could wire it to my generalized classes, but then you could only
>use me and my two sisters, and they're not python programmers.
Let's say that a programmer does a number of tasks, among them are:
'writeRequirements', 'design', 'implement'
In that case it is reasonable to expect that every programmer should
implement those three methods. In which case I can write code like:
# Client code
son = Son ()
if has_attr (son, writeRequirements):
	son.writeRequirements ()
if has_attr (son, design):
	son.design ()
if has_attr (son, implement):
	son.implement ()

Assuming that I had interfaces, I would write:
interface Programmer:
	""""""
	def writeRequirements (self):
		""""""
	def design (self):
		""""""
	def implement (self):
		""""""
		...
class Son (Dad, Mom) implements Programmer:
	...

# Client code
son = Son ()
if implements (son, Programmer):
	son.writeRequirements ()
	son.design ()
	son.implement ()

What are the benefits of using the interface? Documentation is one of the
biggest advantages. Also, an ability to ask the object if it implements
interface as a whole comes in handy and reduces the number of if statements.
Although the version of client code that uses exceptions is as simple.

Now let's assume that there is an inexperienced programmer who does not
write requirements yet, but is capable of doing everything else... It seems
like our interface needs to be split up into two -- Analyst and Programmer

interface Programmer:
	""""""
	def design (self):
		""""""
	def implement (self):
		""""""
		...

interface Analyst"
	""""""
	def writeRequirements (self):
		""""""

class Son (Dad, Mom) implements Analyst, Programmer:
	...

# New client code
son = Son ()
if implements (son, Analyst):
	son.writeRequirements ()
if implements (son, Programmer):
	son.design ()
	son.implement ()

As you can see the client code had to change.

Let's see what would client code withut interfaces look like?
# Client code
son = Son ()
if has_attr (son, writeRequirements):
	son.writeRequirements ()
if has_attr (son, design):
	son.design ()
if has_attr (son, implement):
	son.implement ()

As you can see, the version with if has_attr() still works just fine!
(Assuming that has_attr works...)

The point is -- the proposed definition of interfaces brings very little to
the table. Everythinbg it offers can one way or another be done using
existing language constructs. Sometimes, the use of interfaces introduces
backward-compatibility problems.
The biggest benefit that I see in the PEP 245 is the documentation. I like
the fact that documentation will be structured in the form of the interface
definition as oppose to a sparate help file.
I also like an ability to determine if the object implements interface as a
whole. But I can live without it using introspection.
If the notion of "__getinterfacereference__" were added, I would see a lot
more value in the PEP.

Regards,

Alex Shindich


-- 
Posted from mailgw2.itginc.com [38.149.119.13] 
via Mailgate.ORG Server - http://www.Mailgate.ORG



More information about the Python-list mailing list