A type checking system (was Re: Inefficiency of __getattr__)

Huaiyu Zhu hzhu at users.sourceforge.net
Wed Oct 4 15:11:39 EDT 2000


On Wed, 4 Oct 2000 13:10:06 +0200, Alex Martelli <aleaxit at yahoo.com> wrote:

[Re advandage of static typing]

>Whether these undeniable gains are worth the various components
>of bother that static typing just-as-undeniably adds, is of
>course The Question.  I come from a background of mostly static
>typing, but over the years I've never entirely lost track of
>the dynamic-typing world, and from a LOT of relevant experience
>in both camps I have come to be pretty convinced of two things:
>    -- the whole song-and-dance of mandatory strict static typing
>        where the programmer has to specify everything statically
>        is far too much to pay for the benefits; this means Eiffel,
>        C, C++, Java, Pascal, &c;
>    -- having NO way to specify static typing in the language,
>        even where one would DEARLY LOVE to do so for any of
>        the possible benefits, is going too far in the other
>        direction; this covers Python, Scheme, &c.

That is so true.  And the solution is, as you say, to provide voluntary type
checking.  To be really useful for an OO language like Python, however, it
has to work well with overloading and polymorphism.  Here comes a crucial
observation:

  Types should not be inherited in the same way as classes:
   - class inheritance go the way of specialization, for implementation
   - type inheritance go the way of abstraction, for requirements

These ideas are discussed in (and quoted below)
http://www.geocities.com/huaiyu_zhu/python/Interface/README.txt

and a prototype illustrating the ideas is at
http://www.geocities.com/huaiyu_zhu/python/Interface/typecheck.txt


Here's my take on

		Type checking system in Python

Classes implement a hierarchy of inheritance of attributes (variables and
methods).  They are useful for implementation modularization.

There is another type of modularization that is similar in nature, but is
independent of classes.  This is the hierarchy of polymorphic interfaces.

Python supports polymorphism in a very liberal way: if it walks like a duck
and quacks like a duck, then it must be a duck.  The archetypical examples
is that one can usually substitute a writable file with a user defined class
object that happens to have a write() methods with appropriate property.

In many programs it is necessary to ensure that a certain objects has
certain properties.  But how can we express the idea that a function expect
a file-like object, while that can mean an endless list of things, many have
not yet been defined?

One solution promoted by some other languages is to define some abstract
classes for type checking purpose, and require them to be inherited by any
class that behaves like them.  This is like what interfaces do in Java.
This solution is not satisfactory because

- It breaks polymorphism.  One has to harness the property at the time the
  classes are defined, instead of when they are used.  For example, if an
  application requires a property of "ReadableFile" which is satisfied by
  sys.stdin, it is difficult to retrofit the definition of sys.stdin to be
  an instance of such.

- It mixes two incompatible inheritances.  For example, suppose that class A
  has method A.m() but its subclass B overrides it with B.m().  The property
  A satisfies is not necessarily satisfied by B.

>From the above it is clear that there is a useful conceptual hierarchy that
is independent of the class hierarchy.  For lack of a better name let us
just call them Types.  The overridability means that classes do not imply
Types, and the polymorphism means that Types do not imply classes.  Their
main conceptual difference is that

- classes embody implementations
- Types embody requirements

Another way to describe the difference is

- classes are inherited by specialization
- Types are inherited by abstraction

For example, if we specify that A is a superclass of B, this does not change
anything about A, but it does mean that B will have all the attributes of A.
In contrast, if we specify that A is a superType of B, this does not change
anything about B, but it does mean that objects accepted as B must now be
accepted as A as well.  As a concrete example, consider a function expecting
a Number as an argument.  If we declare that 2.3 is a Float, and Float is a
special case of Number, then the function should accept 2.3 as argument.

Therefore, Types should have their own hierarchy, possibly with its own
syntax, that is independent of classes.  

Since Python is a very dynamically typed system, it is also desirable to
make the type checking as flexible as possible, and completely voluntary,
while being able to deliver the same level of guarantees that a strongly and
statically typed language would give.

Type can also be used to express properties like Immutable, which could only
be guaranteed by a compiler.  These properties will also be very useful for
compiler optimization.

All said, there is a role for classes to play in this affair - It is
possible to fake such a Type system using a class, with some caveats:

- It is dynamic, and very inefficient at run time
- It is dynamic, and can be circumvented in various ways.

Nevertheless, this dynamical type-checking does provide a fine illustration
of the concepts discussed above.  If and when they can be coded in compiler
it will be of much greater use.




More information about the Python-list mailing list