[Types-sig] Interface PEP

Sverker Nilsson sverker.is@home.se
Mon, 26 Mar 2001 18:34:47 +0200


Marcin 'Qrczak' Kowalczyk wrote:
> 
> Fri, 23 Mar 2001 17:41:07 +0100, Sverker Nilsson <sverker.is@home.se> pisze:
> 
> > def f(x:y)
> >
> > The question is: what is the y.
> >
> > 1) 'interface'
> > 2) 'type'
> > 3)  something else
> 
> If you call it 'type', it would be confusing, because the builtin
> function called 'type' would no longer return the type of the object
> (for the new meaning of the term 'type').

Seems you lost me here... It will actually return a type, 'the' type,
for all I can tell. In the body of the function f defined above,
type(x) will be a type that is a subtype of y.

One can argue that there is nothing such as 'the' type of an object.
As you have pointed out, using the term interface. I believe that is
ok though.  What type() returns is in general an over-estimate of the
set of allowed values. It is 'the' type that the object decides it
wants to tell the world it's got. As long as it is not telling us an
under-estimate, it is ok for the object to tell us any type that it is
indeed compatible with.

Thus it seems conceivable that of two otherwise similar objects, for
example of some list implementation, one could tell us it was
SomeListType and the other say it was some more general
SequenceType. To have things make sense in this case, SomeListType
should have been declared to be a subtype of SequenceType.

Noting that otherwise similar objects can answer different type() is
perhaps surprising, but I don't see any real problem or confusion with
it as long as one gets used to it. It's just a matter of life... there
can always be different descriptions.  We may need to pick one
sometimes. Subtype relations may then be used to determine which types
are compatible.

> 
> > You may counter now that types are close to classes as you claimed
> > before, and I agree classes specify specific implementation. But I
> > think I showed in the previous mail how types (that is, what type()
> > returns) is likely to stay separate from classes
> 
> If types and classes are unified but the 'type' function returns
> the same thing as currently, it's clear that it is kept only for
> compatibility - it has an irregular behavior.
> 
> But this is a problem of the 'type' function, not of the unification.
> 
> > it would be no gain making them the same
> 
> Of course there would be gains: you could inherit from files, and

You could still do that, at least from file *classes*: you inherit from
something like metaclass(FileType). I thought I told you this quite
clearly previously!

But see below, having ClassType a subtype of TypeType means you would
actually be able to inherit directly from some objects of type TypeType.

> the language would be simpler and more consistent.

Opinion varies.

> 
> Look: isinstance works for both types and classes. It's because they
> describe essentially the same thing: what defines the behavior of
> the object.

The behaviour, yes. Both types and classes can describe that, as well
as 'interfaces' can. Behaviour is arguably different from
implementation, which is _only_one_ aspect of behaviour. When using
isinstance(), I think it is typically not a particular
_implementation_ one is looking for.  Classes are tied to
implementation, but they happen to be used in isinstance() for lack of
some better way of specifying behaviour in general.

What I have been arguing for is _not_identifying_ types and classes.
I can as well (after some second thought, admittedly) tell you now
that I am not considering separating them completely either. I would
consider a class a kind of type. It's just that all types are not
classes. So I see ClassType as a subtype of TypeType. I think this
could be declared in types.py:

subtype(ClassType, TypeType)

using a suitable subtype-relationship machinery that registered
subtypes with the subtype() call.

The isinstance() type would then take an object of TypeType
as second argument.

As for the functionality of isinstance(), I think it can be usefully
extended to work for user-defined types as well, Interfaces and such.
It should be able to use machinery supplied with those to check type
compliance.

The two checking mechanism I have in mind here, is a subtype
relationship, and an interface checking mechanism. Could look
something like this untested code...


def isinstance(obj, typ: TypeType):
    if issubtype(type(typ), ClassType):
        return original_isinstance(obj, typ) # Do an old inheritance
check
    if issubtype(type(obj), typ):    # Check registered subtype
relations
        return 1    
    if issubtype(type(typ), InterfaceType):
        return typ.check(obj)    # Check the actual object method
signature
    raise TypeError, 'isinstance: Not a type object...'

# I would also put in the type hack i mentioned before to get a
# more general behaviour out of the type() builtin, for class instances.

def type(obj):
    """ Return a generalized type of an object. """
    # original_type is the currently defined type function
    return getattr(obj, '__type__', original_type(obj))

> 
> > So Python types seem to be free to be generalised.
> 
> They cannot be generalized to cover the functionality of interfaces.
> They can at most be generalized to cover classes.

Your mileage may vary. Opinions differ, obviously.

Cheers, Sverker