[Python-3000] my take on "typeclasses"

Talin talin at acm.org
Thu May 11 08:30:15 CEST 2006


Guido van Rossum wrote:
> [Talin]
> 
>> Ordinarily I would agree with you on this point, and in fact I
>> wouldn't even bring it up at all, except for two data points:
>>
>> 1) The proposal to include generic function dispatch
>>    in Python 3000, based on explicit typing.
>>
>> 2) The proposal to remove all forms of type testing
>>    other than those based on isinstance() (in other words,
>>    removing callable, isSequence, isMapping, etc.)
>>    (I'm not including attribute testing here because its
>>    neither standardized nor systematic.)
> 
> 
> Note that these are *proposals*. IMO they are minority proposals and
> I'm doubtful that they will fly as you state them here. (For example,
> see my other post where I mention that generic/overloading functions
> will at best be used to augment traditional class-based dispatch; they
> will play a minor role at best.)

OK. I admit that much of the motivation for those statements is not 
about what you've stated, but a reaction to some of the statements that 
have been made on this list.

> My proposal of removing callable() wasn't intended to increase the
> number of isinstance() calls. Rather, it was intended to face paranoia
> head-on, by saying "just call it!" And (re.sub notwithstanding) APIs
> that depend on being able to distinguish between a callable and a
> non-callable are usually poor API design, and should be replaced by
> other approaches (like keyword arguments).

While it may be true that these are "usually" poor API design, I have 
provided several examples of popular, well-known and well-respected 
Python libraries that use exactly this feature, and for which simply 
calling and catching the exception is not an effective substitute.

I also feel that one can only judge design quality in context, 
specifically designs that would be considered "poor" for Java or C++ may 
be perfectly reasonable for Python. There are a lot of Python APIs that 
have a kind of "do what I mean" quality to them, and I don't see that as 
bad style per se; What *is* bad style is unpredictability and surprise.
A DWIM API can be well designed if the internal behavior exactly matches 
the average user's preconcieved expectations.

> You're way ahead of me here. You talk like this is a done deal. It
> isn't. And in fact I am strongly *against* any kind of "accidental
> paradigm shift" like this -- I'm doing my best to prevent those from
> happening. (There are some *intentional* paradigm shifts planned, but
> they are more about the behavior of some specific built-in types and
> operations such as files, strings and mappings, than about the very
> foundation of the type system.)

OK. I think where Phillip and I are headed is that we see the current 
paradigm as incomplete. I would like to see a system in which explicit 
typing and duck typing are both fully realized, and neither is "second 
class" as compared to the other.

While I think generic functions are cool, the discussion of how to 
design criteria for testing vs. duck types is something that ought to be 
dealt with regardless.

>> I think that I agree with the gist of Tomer's point.
> 
> Well, to most of us it's far from clear what he's trying to say...

Well, I won't claim to speak for him directly. But its well known that 
hierarchical type systems have limitations.

I wrote an article on Advogato a long time ago called "The Platypus 
Effect", which talks about how you have all your nice taxonomies set up, 
you know, mammals are the ones with fur and live birth, reptiles and 
birds lay eggs, and so on - and then along comes a platypus, a 
duck-billed, egg-laying, fur-bearing annoyance, which just *doesn't fit* 
anywhere in your scheme. And you can't just "patch" your taxonomy 
either, you end up having to refactor the whole thing.

> Maybe. Although generic/overloaded functions can easily use types
> Of course there's nothing to stop us from establishing a convention
> that allows one to use a single hasattr() call to test for such a
> thing -- or any number of other approaches whose surface API is a
> single call: isinstance(), hasattr(), implements(), all are at some
> level equivalent. So there's not that much new.
 >
> I think I would encourage proposals here to come up with a lightweight
> and reliable convention. It's okay to require that all sequences types
> must do something specific before they will be considered to be
> sequence by the new testing method -- because if we want to be able to
> reliably distinguish between sequences and mappings, we're *somehow*
> going to have to cut the tie. The convention should address existing
> de-facto categories such as iterable, sequence, file-like, etc., and
> also let users (and especially frameworks and libraries) define their
> own catagories.

I've been thinking about this quite a bit. What about a hierarchy of 
"concepts" that looks like this:

iterable:
    -- An item that can be iterated
    -- Test: hasattr( __iter__ )

bounded_iterable( iterable ):
    -- an iterable whose end is predictable in advance
    -- Test: iterable() + hasattr( __len__ )

indexable( bounded_iterable ):
    -- an iterable that allows random access to its elements
    -- Test: bounded_iterable() + hasattr( __getitem__ )

sequence( indexable ):
    -- an indexable in which the indexes are successive integers
    -- Test: isinstance( index_type, int )

mapping( indexable ):
    -- an indexable in which the indices are hashable values:
    -- Test: hashable( index_type )
    -- (Also test for immutable if its feasible)

So if all you want to do is iterate over an item, you don't test to see 
if its a sequence, you test to see if its iterable. And because you want 
to define your API in such a way as to eliminate surprise, you can use 
the term "iterable" so that everyone knows what you mean. In other 
words, if my function does one thing when passed an iterable, and 
something else when passed a non-iterable, the programmer can then know 
exactly what will happen when they pass their own data type in.

> Bill Janssen is proposing that the specific thing a type must do is
> inherit from some abstract base class.
> 
> Phillip Eby is countering that that isn't sufficient because he wants
> to be able to make up his own categories and apply these to existing
> types defined by 3rd party libraries.
> 
> It would be great if we had a solution that allowed either approach!

Yes indeed.

-- Talin


More information about the Python-3000 mailing list