What static typing makes difficult
aleax at aleax.it
Sat Oct 25 23:06:19 CEST 2003
Brian McNamara! wrote:
> mertz at gnosis.cx once said:
>>The package gnosis.xml.objectify takes an XML source, and turns it into
>>a "native" Python object. The function make_instance() can accept a
>>wide range of different things that might sensibly relate to XML: a DOM
>>object, a filename, an XML string, any object with a .read() method.
>>Just one function deals happily with whatever you throw at it--without
>>any deep commitments about what type of thing it is (i.e. some novel
>>file-like object, or some new DOM implementation work without any
...but since Python doesn't (yet) have protocol adaptation machinery,
you don't really have a good systematic way to extend make_instance
(while respecting the open/closed principle) for another completely
new type of "XML source" that doesn't naturally conform (though it
might be adapted) to any of the required protocols.
I.e., if a third-party library XX generates instances of XX.YY and
feeds them into a callable which happens to be that make_instance,
you have no way of providing adapters of XX.YY instances to the
requirements of make_instance which is not "invasive" in some way
(and, presumably, similar problems with adapting the results of
make_instance to whatever protocol third-party library XX requires).
One gets by, mind you, by being "somewhat" invasive and wrapping
the daylights out of something or other. But, it's definitely not
a point of strength or elegance -- it feels like those plumbing
repairs made with duct tape, and as such it's somewhat of a let-down
compared with many other areas of strength of Python.
Now, compare with Haskell's approach...:
> class ConvertibleToXML a where
> convertToXML :: a -> Maybe XMLRep
> instance ConvertibleToXML DomObject where
> convertToXML :: DomObject -> Maybe XMLRep
> convertToXML aDomObj = ...
> As far as I can tell, the only "extra scaffolding" is the type class
> ConvertibleToXML. Each time some new data type comes along which can be
> converted to XML, we add a new instance declaration which shows how.
Amen. In other terms, WITHOUT modifying some third-party library (nor
in fact this one), you can supply a *PROTOCOL ADAPTER* that is able
to convert whatever novel protocol the 3rd party library supports to
whatever protocol make_instance requires -- the "typeclass", which is
QUITE A BIT more powerful than just an "interface", represents the
protocol, and the instance represents the adapter from some type or
typeclass into the required protocol.
Now, Haskell does it all at compile-time, but that's just because
that's the way Haskell works; just the same thing could be done at
runtime by explicitly registering protocols and adapters. But of
course, having the tools available would be not very useful unless
protocol adaptation was REQUESTED and/or OFFERED by a reasonably
vast subset of standard and third-party libraries -- if you have to
do it all yourself by hand you might as well code more down-to-earth
wrappers as above mentioned.
The best current implementation of the protocol adaptation ideas in
PEP 246, to the best of my knowledge, is PyProtocols,
No, it ain't Haskell, and in particular PyProtocols' interfaces
are NOT as powerful as Haskell's typeclasses (we'd need a LITTLE
extra semantic support from the Python compiler to get those). But,
as the above ConvertibleToXML example shows, you don't ALWAYS need
the full power of typeclasses -- pretty often, using them as little more
than interfaces is sufficient. Moreover, PyProtocols supports
adaptation (including transitive adaptation) even on "alien" interfaces
(which it sees as "opaque protocols", if you wish -- of course you'll
have to code the adapters WITH knowledge of the alien interfaces'
semantics, PyProtocols cannot do that for you, but it can support you
with registry and dispatching to suitable adapters), NOT just its own.
More information about the Python-list