[Python-3000] PEP 3100 Comments

Phillip J. Eby pje at telecommunity.com
Tue May 9 16:18:58 CEST 2006


At 06:19 AM, 9 May 2006 +0000, Talin <talin at acm.org> wrote:
>Now, generic functions are good at dealing with these kinds of
>situations. However, generic functions (as they are usually concieved)
>can only deal with specific, concrete types, not "types which satisfy
>some constraint".

In Haskell, interfaces are defined using "typeclasses".  A typeclass is 
basically a collection of generic functions.  For example, you could define 
a "sortable" typeclass that includes the generic functions for "less than" 
and "equal to".  You can then define a function as taking a "sortable" 
parameter, and it then accepts only values that can be passed to "less 
than" and "equal to".

Further, Haskell has a concept of "typeclass instances" which basically 
give you adaptation.  For example, suppose I have some generic functions 
other than "less than" and "equal to", that do basically the same thing for 
some set of types.  For example, maybe there's some library that has "lt" 
and "eq" functions.  I can define typeclass instance for "sortable" that 
maps "less than" to "lt" and "equals" to "eq" automatically.

With these two features, you get all the remaining benefits of interfaces 
and adaptation, without any of the headaches caused by more traditional 
type systems.  You never have to explicitly declare support for an 
interface, unless you're effectively defining adaptation from a different 
interface.  And anyone can easily define new subsets of "dict-like" or 
"file-like" interfaces containing only the operations they need, because 
these interfaces are just a collection of generic functions that can be 
mixed and matched at will.

In Haskell, a lot of the work can be done by type inference, in that if you 
use "less than" and "equal" generic functions in the body of a method, the 
compiler can usually infer what types that method can thus be applied to, 
without the need to create an explicit typeclass or  type declarations.

(You couldn't get quite that implicit in Python, though; you'd have to have 
at least explicit declaration that you wanted a "sortable" parameter or a 
"mapping" argument.)


>So the question is - how does the person writing their own sequence
>type indicate that their type is to be treated as equivalent to a
>sequence, at least for purposes of my API?

Well, in the generic function world, it would be by defining methods for 
sequence generic functions like len(), iter(), operator.getitem(), and so 
forth.

If we had syntax support for defining such methods, you might do it with e.g.:

      def operator.getitem(self, key):
          ...

which is curiously reminiscent of certain other languages' operator 
overloading.


>A second, related question is - how much like a sequence does the
>object have to be? For example, there are many APIs that really only
>care if the object is iterable or not.
>
>Most APIs use only a fraction of the full capabilities of a type - so
>perhaps what is needed is a way to test only those capabilities. For
>example, instead of "isSequence" we could have "isIndexable",
>"isIterable", and so on.

You mean, like by being able to ask a generic function if it supports a 
particular type signature?  ;)


>Of course, we could instead somehow mandate that by deriving from that
>base class, you are required to implement those methods. However,
>that's just a fancy way of saying "interfaces a la Java". Interfaces
>are good, but they don't allow the kind of isolation that true duck
>typing allows.

Or that generic functions allow.  :)



More information about the Python-3000 mailing list