[Types-sig] A type checking system in Python

Huaiyu Zhu huaiyu_zhu@yahoo.com
Wed, 21 Mar 2001 18:41:07 -0800 (PST)


On Wed, 21 Mar 2001, Paul Prescod wrote:
> Sorry, I didn't realise that this was an older post that had been
> revived! I thought you were in sync with our current efforts. 

I saw the PEP by Clark on c.l.p, so I posted the doc and py from my page

http://www.geocities.com/huaiyu_zhu/python/Interface/index.html

There are a few more things there.

> 
> > ...
> > This may be more flexible than what is normally called polymorphism.  So
> > let's call it strong polymorphism.  In any case, it is routinely used in
> > Python.  It is not supported by Java interface.  In Java, I do not believe
> > you can define an interface in user code, and then retro-actively declare
> > that some imported class satisfy this interface.  I would not want a
> > typechecking system in Python without strong polymorphism.
> 
> I do not have any problem with strong polymorphism but I think that
> people tend to overstate its value. The reason that you can use file
> objects and mapping objects so easily between Python modules is because
> those interfaces were informally defined by Guido years ago. It seems
> extremely unlikely to me that there will arise many cases where you just
> happen to have an object that just happens to have the right methods
> with the right parameters and semantics. This will only realistically
> happen where there was an explicit or implicit interface definition that
> both programmers knew about.

But I use this everyday when I use python.  Say I want a sequence, which
could be [], (), UserList, but not string.  How do I specify that?   I do

def is_my_seq_type(x):
   return type(x) is type(()) or type(x) is type([]) or isinstance(x, UserList)

def f(x):
    assert is_my_seq_type(x)
    ...

There are many different places I want a certain behavior.  It is very
unlikely it could all have been designed before hand.   Java is an example
that all interfaces are designed before implementation (because the language
forces you to do so).  Look how complicated the class system becomes!

Another example.  Say I define a type LocalSource, which includes
sys.stdin, open("data"), but not urllib.open(url).  If I want requirement,
should all of those implementations (stdin, open and urllib.open) know
whether they satisfy this requirement?  No way that can be done in practice.

> >..
> > The distinction in my proposal is that Types (or call it interfaces if you
> > like) should inherite the other way round.  When you check
> > 
> > a is of Type b
> > 
> > you should not ask a: "Are you of type b?"  You should ask b: "Do you
> > include a?"
> 
> Most practically, I think that you should ask a about b AND b about a.
> Then maybe you even ask a third-party registry about whether an adapter
> exists to bridge from one to the other.

Right.  That would be even better.  Actually what I call Type is exactly
what you call registry, albeit implemented in a distributed way.  The key
point is that the object a itself should not need to keep track of this.

> 
> > In a good design, an object should be able to satisfy an infinite number of
> > interfaces, most of which do not yet exist, without knowing anything about
> > them.
> 
> I think that this is really only practical with some kind of adapter
> layer. It does not seem realistic to expect objects to magically have
> the right methods that some third party code "happens" to need. For
> instance if you invent a WebBrowser object and I invent a WebBrowser
> interface separately, the chances of them lining up automatically are
> almost nil. But you could create an adapter that bridges from one to the
> other so that conversions back and forth happen whenever necessary.

Could you explain what an adapter layer is?  Are you thinking about some
kind of casting between different Types (or interfaces)?  I was talking
about type checking only, for which there is no need to lining them up.  You
just say

my_required_webbrowser = Type()
my_required_webbrowser.add_obj(WebBrowser_a)

Then of course WebBrowser_b would not be of this type unless you also add it
in.   Just like you can do

ReadableFile.add_obj(sys.stdin)

without dragging in sys.stdout, which would be wrong.  I could think of a
large number (say hundreds) of requirements like ReadableFile, LocalSource,
etc, that sys.stdin might satisfy in practice.  There is no way, and not
practical, to require sys.stdin to know all the ways it might be used.

 
> > I just glanced over this.  Is there a text description of this?  From what I
> > see, it seems that you want the types be predefined.  Can the user add type
> > later on and declare whatever object he has as being of this type?
> 
> Yes, you can add types whenever you want. No, you do not declare
> conformance to a type. That is separate work. Michel Pelletier is
> working on a conformance declaration infrastructure and so is Clark
> Evans.

If you don't declare conformance to a type, then I can see why you think a
type would be rarely aligned.  In my approach the programmer declares such
when he knows it conforms.  Have you tried the code attached?

I think I need to read more about what the type-sig did before speaking
more.  If I have missed the point in the above, please let me know.

Huaiyu