[Types-sig] Interface PEP

Marcin 'Qrczak' Kowalczyk qrczak@knm.org.pl
14 Mar 2001 20:36:07 GMT

Wed, 14 Mar 2001 14:20:22 +0100, Sverker Nilsson <sverker.is@home.se> pis=

> The type() builtin would return, as usual, InstanceType if the
> __type__ special attribute was not defined. Otherwise it would return
> what __type__ returned. - which would be a user defined type (aka
> interface) or even a builtin type, if the class wants to claim it
> emulates a built-in type.

Warning, warning! This is a wrong way.

There is no concept of asking an object which interface it implements.
There is no "the" interface it implements.

It's not even a set of interfaces, because the object doesn't know
them in advance. Interfaces can be defined after objects conforming
to them are created.

This is a thing which languages like Java, Eiffel, OO Pascal extensions,
C#, and the OO part of C++ got wrong. They require the object to know
interfaces it implements. This limits the flexibility of interfaces.
This is a reason why languages like Python are dynamically typed.

Interfaces can be designed well in statically typed languages.
Haskell, Clean, Mercury, OCaml, the template part of C++ (poorly),
and an extension of g++ called "signatures" (to be dropped or already
dropped) - don't require the object to know its interfaces in advance.

Some of these (especially the Haskell / Clean / Mercury solution)
also don't require to list a single interface when specifying what
argument a function accepts.

This is done in various ways:

* Haskell, Clean and Mercury have a powerful system of what they
  call "classes". They should be called "interfaces". A separate
  declaration asserts that a type conforms to an interface, by
  providing implementations of methods the interface requires. Methods
  don't have a distinguished object they act on but look like plain
  functions - e.g. (+) is fully symmetric.

* OCaml has an OO class system where interfaces are implicitly created
  by listing methods with their types (of course you can bind them to
  names). An object conforms to an interface if it has these methods
  with compatible types.

* C++ doesn't have interfaces formally in the language. A template
  can be instantiated on any type. If the type provides the right
  functionality (by having appropriately named functions overloaded),
  the program works. If it doesn't provide it, the program may or may
  not compile, may or may not work properly, and it may depend on
  the version of the library (which parts of the interface it uses
  in which way). Interfaces are only roughly defined and are only
  described in human languages.

* C++ signatures are similar to OCaml in the concept, but with much
  worse quality of design and implementation.

It would be silly to lead Python to the wrong direction, exemplified by
Java and the OO part of C++. Given how Python looks today, it will not
be accepted, because having to design all interfaces from the beginning
is too constraining. The failure will be attributed to static typing.

So what to do? The Haskell / Clean / Mercury solution is probably
too far from Python. The template part of C++ is approximately what
we have today, only without static typing.

We can aim at the OCaml / C++ signatures direction. So an interface
is defined by listing method names and requirements. It can be given
a name, but a class doesn't need to list interface names in order
to conform to them. Of course objects don't know their interfaces,
similarly as they don't know names of variables they are bound to.

We can also aim at the way I described as wrong, provided that it
is sufficiently dynamic. So an object or a class keeps the list of
interfaces it implements, and they can be added on the fly later.
This way is less formal if conforming to a protocol is not checked
but declared.

We can try a combination of both.

Or something completely different.

 __("<  Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/
  ^^                      SYGNATURA ZAST=CAPCZA