[Python-Dev] proposal for interfaces

Esteban U.C.. Castro esteban@ccpgames.com
Sat, 28 Sep 2002 08:26:38 -0000

Hi, I have just joined python-dev and I saw your very interesting
for implementing intefaces.

> I have an idea for an interface mechnism for Python, and I'd like to
see if
> anyone likes it before writing an actual PEP.  [...]

I like it a lot! Anyway, if it can be implemented in python as is, what
the point of the PEP? Making the 'interface' root class and/or
builtins, maybe?

I have some comments which I thought I would bounce. I'll organize these

attending to the activities they relate to. Don't hesitate to tell me if
sayig something stupid. :)

Define an interface

In your example, it seems that

  class Foo(interface):
    def default_foo(self, a, b):
      "Docstring for foo method."
      print "Defaults can be handy."

[I added the a, b arguments to illustrate one point below]

Does the following:=20

 - Defines the requirement that all objects that implement Foo have a
 - Defines that foo should accept arguments of the form (a, b) maybe?
 - Sets a doc string for the foo method.
 - Sets a default implementation for the method.
Some questions on this:

 - Can an interface only define method names (and maybe argument
   I think it would be handy to let it expose attributes.

 - Is method names (and maybe format of arguments) the only thing you
   'promise' in the interface? In other words, is that the only type of=20
   guarantee that code that works against the interface can get? I think

   a __check__(self, obj) special method in interfaces would be a simple

   way to boost their flexibility.

 - For the uses you have given to the prefix_methodname notation so far,

   I don't think it's really needed. Isn't the following sufficient?
 class Foo(interface):
    def foo(self, a, b):
        "foo docstring"
        # nothing here; no default definition
    def bar(self, a, b):
        pass # no docstring, _empty definition_

This has the side effect that a method with no default definition and no

doc string is a SyntaxError. Is this too bad?=20

- It would maybe be hard to figure out what such a method is supposed to

  do, so you _should_ provide a docstring.=20

- If you're in a hurry, an empty docstring will do the trick. While in=20
  'quick and dirty mode' you probably won't be using interfaces a lot,=20

Defaults look indeed useful, but the really crucial aspect to lay down=20
in an interface definition is what does it guarantee on the objects that

implement it. If amalgamating this with default defs would otherwise=20
obscure it (there's another issue I'm addressing below), I think
belong more properly to a class that implements the interface, not to
interface definition itself.

I guess knowing what other uses you have in mind for the
notation could be useful to decide whether it's warranted.

Check whether an object implements an interface

>From your examples, I get it that an object implements an interface iff
is an instance of a class that implements that interface.=20

So I guess any checking of the requirements expressed by the interface
done at the time when you bind() a class to an interface.

This paradigm perfectly fits static and strongly typed languages, but it

falls a bit short of the flexibility of python IMO. You can do very
things to classes and objects at runtime, which can break any
based on object class.

In your example:

  def foo_proc(foo_arg):
    foo_proxy =3D Foo(foo_arg)
    x =3D foo_proxy.foo(a, b)

[added a, b again]

imagine foo_proc may only really cares that foo_arg is an object that
a foo() method that takes (a, b) arguments (this is all Foo guarantees).

 * Will the Foo() call check this, or will it just check that some class
   in foo_arg's bases is bound to the Foo interface?=20

   In the second case, if someone has been fiddling with foo_arg or some

   of its base classes, foo_arg.foo() may no longer exist or it may have

   a different signature.

 * Why should Foo() _always_ fail for objects that _do_ meet the
   expressed by the interface Foo but have _not_ declared that they
   the interface? If the point is to avoid false positives, interfaces=20
   with this concern may still make the class check:

  class Foo(interface):
      def __call__(self, obj):
          error =3D __check__(obj)
          if error:
              raise InterfaceError, error
              return self.proxy(obj)
      def __check__(self, obj):
          if not hasattr(obj, "foo"):
              return "No method foo found"
          return interface.check_class(self, obj)

Making such check optional allows implicit (not declared) interface=20
satisfaction for those who want it. This should extend the applicability

And this brings up another problem with defaults: they would increase
positives. What if an interface wants to provide defaults for all its
Will then any object match it? This would force additional checking.=20

Even thought this doesn't look like a big issue to me, I think it's
to leave validation for interfaces and implementation for classes.

Declare that an object implements an interface or part of it



* I agree the declaration had better be included in the class
definition, at=20
  least as an option.=20
* Declarative better than procedural, for this purpose.
* Only classes (not instances) can declare that they implement an
* Indexing notation to 'resolve' methods a bit counterintuitive.

What about:

  # interfaces=20

  class Foo(interface):
      def foo(self, a, b):=20

      def clash1(self, x):

      def clash2(self):
          ...      =20
  class Bar(interface):
      def bar(self, x, y):

      def clash1(self, a, s, d, f):

      def clash2(self):=20
          # actually equivalent to Foo.clash2
          # we should really factor this out in one interface
          # but imagine we can't do so for some reason...
          ...   =20

  # implementations

  class SomeClass:

	# promise that all instances of SomeClass will implement Foo and
      __implements__ =3D (Foo, Bar)=20

      # automatically assumed to implement Foo.foo()   =20
      def foo(self, a, b):=20

      # There is not automatic name clash resolution. InterfaceError
	# we resolve these explicitly
      def fclash1(self, x):
      fclash1.__implements__ =3D Foo.clash1   # maybe we should require
							  # to be a
tuple too?

      def bclash1(self, x):
      bclash1.__implements__ =3D Bar.clash1

      def clash2(self):
      clash2.__implements__ =3D (Foo.clash2, Bar.clash2) # or maybe this
# not really needed?
# seems to reflect bad=20
# design anyway

  # 'Remove' an interface from a subclass without actually removing it
  # the base (or just cut the search with negative result):
  class Child(SomeClass):
      __implements__ =3D (-Foo,)  # will be found before the 'Foo' in =
					  # class

  # an object that is *not* an instance of a class that implements Foo
  # to play the Foo

  obj =3D Child()
  obj.foo =3D lambda a, b: ...
  obj.clash1 =3D lambda x: ...
  obj.for_the_fun_of_it =3D lambda: ...
  obj.__implements__ =3D (Foo,)   # will be found before the '-Foo' in =

					  # class

  obj.for_the_fun_of_it.__implements__ =3D Foo.clash2 # object dict will
searched first


This is, to make sure that an object is only accessed in the ways=20
defined in the interface (via the proxy).=20

This should be optional too, but your syntax does this nicely; you
can call Foo() as an assertion of sorts and ignore the result.

Note that the __implements__ method resolution magic would require=20
that you get a proxy, though.

What do you think?