[Types-sig] Interface PEP

Marcin 'Qrczak' Kowalczyk qrczak@knm.org.pl
21 Mar 2001 20:00:19 GMT


Wed, 21 Mar 2001 17:55:57 +0100, Sverker Nilsson <sverker.is@home.se> pis=
ze:

> How about the type() builtin. I assume we can't remove it or rename
> it to class() because it may break too much code. What should it
> return for an instance of a user-defined class then?

Deprecate it. Let it behave as currently, but it has no place when
types and classes are unified. Have another function which returns
the unified type/class of an object.

Or change it. Let it return the class object instead of InstanceType.
Use from __future__ or another mechanism to make the transition smooth.

I don't care. I'm not talking how to smoothly apply this unification
to existing Python, but how a Python with unified types+classes would
look like.

> Granted, he seem to regard this mostly as a temporary solution,
> but I don't see why it can't be part of the permanent solution.

Because the special status of builtin types is only an artifact of the
current implementation. The split doesn't carry a meaningful message.
The same thing can be often done as either type or class.

> Builtin Python types happen to specify specific implementations.
> I still don't see why we can't have something more we call types,
> user define types, that happen to specify another implementation
> (such as the implementation shared by all InstanceType objects)
> but mostly are used to specify a protocol/interface.

Because interface is the opposite of implementation!

The point in an abstract interface is that it does not say anything
about the implementation.

A type defines an implementation (and indirectly some interface,
but parts of this interface are shared by many types and classes).

A class defines an implementation (and indirectly some interface,
but parts of this interface are shared by many types and classes).

An interface doesn't restrict the object to have a particular type or
class. It only says how the object can be used. Interfaces are not
formalized in Python, but could be, and the purpose of this list is
to design an interface framework and concrete interfaces in it.

Type and class are almost the same concept. Interface is a completely
different concept.

> That said, I believe it would be good to have a single way to
> refer to what we put as the type-indication. If we have this syntax
> for example:
>=20
> def f(x:y)
>=20
> What's the y? Most languages call it a type, I think.

It doesn't matter how they call it. It matters what it means.

Since it determines what f assumes about x and which objects
are acceptable for x, it seems natural to call it an interface.

For example "sequence" and "file-like object" are already existing
Python interfaces, even if not strictly defined.

If f indeed requires x to be a specific type or class, and it's
not enough for x to have specific methods with specific signatures
and meanings, we can make an interface from a type or a class. Such
interface is quite constraining: it requires an object to have the
specific type or inherit from the specific class.

For convenience we can allow type objects and class objects to be
used as interfaces directly, instead of having to explicitly obtain
the interface generated by a type or class.

> In Haskell you could specify interfaces AND types, when defining
> the type of an object. They are specified in different ways. You
> can say, if I remember correctly, for example:
>=20
> f:: Integral a, Integral b =3D> (a->b)->Tree a->Tree b
>=20
> where Integral is a class (interface) and Tree is a parameterized
> type.

Indeed.

> Type specifications can get long. But you can't define a type that
> contains all the above - this is not allowed, IIRC:
>=20
> type atype =3D Integral a, Integral b =3D> (a->b)->Tree a->Tree b

This is because class constraints are not a part of the type.
You can at most write
    type AType a b =3D (a->b)->Tree a->Tree b
and then
    f :: (Integral a, Integral b) =3D> AType a b

This signature of f is identical to
    f :: (Integral c, Integral d) =3D> AType c d
Names of type variables are not a part of a complete type.

It would be meaningless to have type variables in the definition
which are absent in the left hand side, i.e.
    type Spam =3D a -> b
Such type doesn't exist by itself. Type variables have a meaning
only in the context of a complete type of a variable.

> That's an unnecessary restriction, I think. Even though it may be
> necessary in the context of the specific Haskell system of types,
> it should not be necessary in general to keep interfaces and types
> that rigidly separated.

It's a syntactic detail. Having to express interfaces as types (as
in Java and Eiffel) has more serious restrictions. It is generally
wrong in its core assumptions. Some interfaces can only be considered
properties of types, not of objects of these types.

In Java and Eiffel you cannot say that two arguments of a function
have a type which supports a sequence interface. You can say that they
are both sequences, but it's not enough to be able to concatenate them
(let's assume that sequences must support concatenation). You cannot
concatenate a list with a tuple, or a tuple with a string. But you
can concatenate two lists, or two tuples, or two strings. In general
you can concatenate two objects of the same type if it's a sequence
type. You cannot express this by interfaces of individual sequence
objects.

You cannot say that a function can be called with a list of objects
of some comparable type, and will return an object of that type,
no matter what type it is.

You cannot say that the first argument is a mapping, and the second
argument has the matching type for its keys, and the result has the
matching type for its values.

You cannot say that an object is both a mapping and something which
can be written to a file.

You cannot say that an argument is a (possibly empty) list of
"statements" producing values of some type, let's call it a, and
the result is a "statement" producing a list of values of type a.
"Statement" means an object whose type supports the "statement"
interface, call it "monad", which defines how to compose statements
and how to make a trivial statement returning some value. The assertion
that the function f has this type is spelled thus in Haskell:
    f :: Monad m =3D> [m a] -> m [a]
and thus in C++ (including the comment):
    template <template <typename> class m, typename a>
    m<list<a> > f (const list<m<a> > &);
    // m must be a monad.

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