[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