[Types-sig] Interface PEP

Sverker Nilsson sverker.is@home.se
Thu, 15 Mar 2001 01:31:22 +0100


Marcin 'Qrczak' Kowalczyk wrote:
> 
> Wed, 14 Mar 2001 20:53:05 +0100, Sverker Nilsson <sverker.is@home.se> pisze:
> 
> > Well, what I can agree with is that the interfaces are _descriptions_:
> > more for the human reader, than for (dynamic or static) type-checking.
> 
> They are both for humans and for the interpreter / compiler.
> 
> > I could consider the type of an object to be something different
> > than the interface, but then _also_ different from the class,
> > contrary to what you imply below.
> 
> There are always problems with underspecified terminology. Especially
> the area of types, classes, interfaces, subtyping / subclassing /
> inheritance, polymorphism is really confusing... The same terms are
> used in the context of different systems or languages with different
> meaning. Easy to be confused or misunderstood.
> 
> Python uses terms "type" and "class". There are several builtin
> types. Object created as class instances all have the same type
> (InstanceType), and can be further distinguished by their classes.
> Many people agree that it would be cleaner to unify these concepts
> in future.

Though I'm sure you know more about this than me, I will still argue
from my ignorance. Here we go:

What not only many but perhaps all people would agree on, including
me, is that the builtin types or classes should be unified with
user-defined classes in this way: So that user-defined classes can
inherit from the classes that the objects with builtin types have.

That doesn't necessary mean unifying types with classes. It could just
as well mean that we defined the classes of the builtin objects.

I.E we would still have types.ListType that would not be an inheritable
class, but we would also have e.g. BuiltinClasses.List.

That I would think should solve the problem that people have with not
being able to inherit.

If it is cleaner or not, compared to making ListType a class, I wan't
argue much about unless but saying that it is, well, arguable :-)

Why would it be cleaner to unify type and class, given the many
variants that exist, that you describe (some of) yourself below?

> 
> C++ uses terms "type" and "class". There is a similarity to Python's
> usage, but in C++ there is no single InstanceType: some types are
> classes, some are not classes. Class templates aren't types yet.

Yes C++ I know some about; that didn't stop me from, for some reason,
considering types as naturally distinct from classes... maybe because
I've been using Python so much lately!

> 
> Eiffel uses terms "type" and "class". Class is the basic unit of
> modularity (how an object is defined), type describes an interface
> (what do we expect from an object). Each non-parametrized class
> yields a type. Each parametrized class may yield a type when applied
> to appropriate arguments.

Humm... thanks for explanation... below you say that Eiffell had
problems with having to analyze too much to see if a class would
yield a subtype.

But here you seem to say that type is separate from class, and it
describes an interface.

So the problems you say they had, seem to be the same whether they
called the type a type or interface.

The problem might have to do with that the class 'yields a type'.
It would be yielding an interface, with other terminology.
I think you said this was the wrong approach in the other mail.
But maybe this is what dynamically typed languages want to do.

> 
> Haskell and Clean use terms "type" and "class". Type defines an
> implementation and functions often require a concrete type. Class
> defines an interface. Types may conform to classes. Functions may also
> require that the type of their argument conforms to some classes. This
> is quite backwards compared to Eiffel and OO theoretic terminology.
> Parametrized types are unified with types, i.e. types of concrete
> objects are special cases of parametrized types in general.

I used Haskell some time but gave up partly because I felt the type
system was constraining and I was afraid of running into walls long
into the project if things wouldn't fit together as planned...  as
they never do. 

Of course statically typed shares some problems; easy refactoring was
mentioned, perhaps on this list, as a big advantage with dynamically
typed languages.

Haskell is arguably one of the more sofisticated. Still they had
problems defining general container classes, at least before they
introduced dual inheritance. (I don't know if that's there now
officially, I remember it was controversal.) And I read some paper
that showed how impossible it was to define a natural join... in some
context.


> 
> OCaml uses terms "type" and "class". Type defines an implementation and
> functions often require a concrete type. The OO subsystem introduces
> classes (templates of objects with method definitions) and class types
> (interfaces of objects with method signatures). A class type is a type.
> A class is something between an object and a type. I hope I got it
> right - I don't have an experience with OCaml's OO subsystem.

I'd be happy to use OCaml for its superb speed, have looked just a
little in it, but may be held back afraid of future refactoring
problems due to the static type system.

BTW, does it have any dynamic types at all?

> 
> We have plenty of definitions to choose from :-)

Right :-)

> 
> > > Interfaces".  One class, or "type" of object, can implement multiple
> >
> > So you identify the object's class with its type... why?
> 
> In Python they have the same purpose. A type, combned with a class
> (in case of InstanceType), describe the implementation of an object.
> Well, partially: object attributes can be different for each object.

Ok well, I thought they as well described the interfaces, at least
partially.

> 
> Interfaces of objects are not described formally in Python nor checked.

Not formally but informally. I think it is quite common to check
if an object has a given method, and not care about its class.

You can never know all about an interface, can you?  I'd say there is
always a matter of degree how much you know.  Types or interfaces are
open-ended: from specifying Integer, in range 1..10, to is_prime(x),
to... whatever.

Since it's open-ended, I would say that we already know something
about interfaces. We know what interface the built-in objects use.
We know the basics about any class's interface: they all either
respond to a method by executing some code or raise the
AttributeError.

Since we know something, it's about being able to know more, and
to be able to extend it in the future, preferrably on user level.

That leads to me arguing that InstanceType is the type of a class
that you don't know much about, except that it's a class.

It's just a special case. Extending our knowledge could be made by
having the class type be something more specific than InstanceType.

Possibly the type could be dynamically generated and contain a pointer
to the object, to allow for generality in checking that the methods
are compatible with some other type (interface).

But it could also just be a declaration saying that 'I am a sequence'
and then we should be able to trust that it has those methods...  we
can't prove it anyway. Just checking that it's got the methods doesn't
help because they may all just be null methods.

I think it should be useful to be able to declare types/interfaces that
claim... well anything, like 'I am a prime'.

> One of current goals is to change this.

Right... actually I came into this discussion more or less by
accident so well, it's their or your's goal :-)

> 
> > Well I'd say "lots of different _classes_ of objects.."
> > Not types of - that would again prematurely fix what we mean
> > with the type of an object.
> 
> I assume that we use the term "type" as currently defined in Python,
> and don't change that.

Now it just means the types defined in types.py. Right?
Are you saying that no more types should be added, except by
new builtin objects?

And are you saying that we cant add more functionality for the types,
like type.is_supertype(other)?

I mean, is that because that would change the meaning of the term
"type"?

Or is it because of that the builtin type(object) could return
something else than InstanceType? - if the designer of the class so
whanted. Would that redefine the meaning of "type" from how it is
currently defined, and if so, in some bad way?

Or what do you mean you are assuming?

(Sorry if the questions above look rethoric, they are not :-)

> 
> > I'd say SequenceType or MappingType should be types just as well
> > as ListType.  Why make them different kinds of things?
> 
> ListType describes an implementation, i.e. how an object was
> constructed. There is a particular object layout and particular
> methods.

When something has type ListType you know its particular methods. 
So why doesnt ListType define an interface too?

It also defines a particular object layout as you say. I'd say that
should be considered a part of the interface, too. Only a part that
most Python functions wouldn't care about - relevant only for
extension functions and the compiler. But a relevant interface
specifcation, nevertheless.

So I don't see any significant difference, just the additional
interface specification for the implementation/object layout.

> 
> SequenceType describes an interface, i.e. how an object can be used.

How an object can be used, isn't that exactly also what ListType
describes?  I mean, not explicitly, but knowing it is a ListType, you
know implicitly all about how it can be used. Making it explicit,
e.g. by defining a function type->description, shouldn't change what
a type is.

> An interace can include things that "len(o) is defined and means blah
> blah" - it doesn't matter how len is dispatched.

Sure. But why couldn't it include a specification of how it's
dispatched too, if it wanted for some reason.

> 
> > I'd say ListType is a _subtype_ of SequenceType.
> 
> A basic misunderstanding of some languages is confusing subtyping
> (the ability to use one type if another is required, i.e. a relation
> on interfaces) and inheritance (basing a class definition on another
> class, i.e. reusing the implementation).

So if I am understanding you correctly:

The problem is you get a type (= class) that is based on a particular
implementation? And not being able to control the interface separately
from the implementation? 

Yes in C++ there is no interface concept separate from classes, right?
And the type is the same as the class.

But I was separating the type from the class.

> 
> Eiffel has problems because of this. It requires checks of the whole
> assembled system to see if a subclass yields a subtype or not.

See previous comment about your description of Eiffel. Isn't the
problem really that it tries to yield an interface (or type, whatever
we call it)?

I can believe there could be problems doing that statically and
optimally.

I'm not arguing much about that now because it wasn't my idea
originally to have an __interface__ field in the objects. Although I
think that it could be good to have.

I just wanted to call it the type instead. This problem with Eiffell
seems irrelevant to that.

> 
> C++ and Java have lack of expressiveness because of this. They
> require some casts because a method signature can't change in an
> inherited class.
> 
> I don't say that you claim that subtyping is the same as inheritance.

Right.

> But you try to unify types / classes with interfaces, which doesn't
> work well.

No I wasnt trying to unify to 1 concept. Just to 2 concepts: types
and classes.

I wasn't aware that types must/should be the same as classes. We have
types and classes. Why join them and then introduce a new concept,
interface?  I'd like to improve functionality of types, by unifing
them with interfaces but keep them separate from classes.

Do we need 3 concepts - types, interfaces, and classes?

> 
> A type / class may generate an interface requirement: namely that an
> object is of this class or a subclass (the "or a subclass" part is
> very problematic). An interface may generate a type / class definition:
> we may want to hold an arbitrary object conforming to an interface.
> They are sometimes blurred, but they are definitely different concepts.

I think this problems disappears since I am not talking about unifying
classes with interfaces, just types with interfaces, and divorcing
types and classes.

> 
> We can have two interfaces (e.g. "comparable" and "convertible to
> a string"). One object conforms to the first but not to the second,
> another conforms to the second but not to the first. This situation
> cannot be described by locating the object's type in the interface
> tree and checking its supertypes. It's not a tree.

Same here, I think, no problem because type != class, although I am not
sure I am following you in this example.


Sverker