[Types-sig] QueryProtocol

Marcin 'Qrczak' Kowalczyk qrczak@knm.org.pl
22 Mar 2001 23:30:01 GMT


Sun, 18 Mar 2001 22:30:13 -0500 (EST), Clark C. Evans <cce@clarkevans.com=
> pisze:

>  "The deep(er) part is whether the object passed in thinks of
>   itself as implementing the Foo interface. This means that
>   its author has (presumably) spent at least a little time
>   about the invariants that a Foo should obey." -- Guido
>=20
> and
> =20
>  "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=20
>   know them in advance. Interfaces can be defined after objects
>   conforming to them are created." -- Marcin 'Qrczak' Kowalczyk=20
>=20
> Mostly beacuse I see them as complements.  Indeed, this distinction
> between "declarative, I am a such-and-such" vs "descriptive, It
> looks like a such-and-such"  are at the basis of Paul's proposal,
> with two type check methods.

Actually my view can be declarative too. It is stolen from Haskell
where it *is* declarative.

It's more about not specifying interfaces at the point of a class
definition than about the method of their specification and checking.
It was an opposition to someone suggesting that a class should be
immediately associated with the interface it implements.

Since in Python everything happens at runtime and everything is
passed by reference, interface+class associations can be created
outside interfaces and classes but stored inside them. Either the
interface or the class may hold them. It depends whom we will ask
whether a class conforms to an interface and from where we will get
the implementation of methods specified in the interface.

IMHO they belong more to interfaces than to classes. Types and classes
would be registered in interface objects, not vice versa. An interface
can specify a combined requirement about a tuple of classes. Properties
can be added to classes but not to types. We already have dispatching
on the object side, namely plain methods. So it's time for something
completely different.

The decision about the level of checking of the conformance, and
details of dispatching, are up to the interface object. An interface
can fail when a class was not explicitly registered. Another interface
will be more liberal and try to deduce the details of conformance
basing on properties of objects, e.g. whether they have attributes
of some names.

A direct translation from Haskell would make the assertion that
a type conforms to an interface look thus:

    instance Hashable(C): # C is a class.
        def hash(obj):
            return obj.spam ^ obj.eggs

The function Hashable.hash(x) works as long as the type / class
of x has been registered... Well, this particular interface has a
default which applies to all classes, namely id, so this is a "soft"
interface which always succeeds.

It's not very clear for me yet how an interface definition would
look like. It's hard to apply the Haskell's solution without having
the rest of the type system. It must somewhat specify patterns of
types of methods in terms of the classes for which instances are
declared. Something like this for a sequence with concatenation,
ignoring the fact that element types are completely unspecified:

    interface Sequence(S):
        def getitem(S, Int)
        def len(S)
        def concat(S, S) # Arguments are symmetric. The choice of S
                         # for a particular usage of Sequence.concat
                         # is deduced from both.
        #def empty() # This doesn't work: there is no S to dispatch on.
                     # It works in Haskell where it's enough to dispatch
                     # on the type of the return value, because it's done
                     # statically.

    # A function which uses the Sequence interface in a generic way:
    def join(*args):
        return reduce(Sequence.concat, args)
        # I would like to say:
        #     return reduce(Sequence.concat, args, empty())
        # The empty() case doesn't work. It won't work in current Python
        # because the empty list of strings is indistinguishable from
        # the empty list of integer lists.

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