[Pythonmac-SIG] Re: improving appscript architecture
has
hengist.podd at virgin.net
Fri Jul 9 01:17:57 CEST 2004
Thanks to Russell and Gary for comments and links on implementing
mix-ins in Python. Related to that subject, here's a quick question
about using "non-standard voodoo":
Given that I'm angling for appscript's eventual inclusion in the
standard MacPython library, the code needs to be grokkable and
maintainable by others (lest I be hit by the Proverbial Bus someday).
How would using something like a home-rolled mixin scheme affect
that? e.g. Justifiable under certain circumstances? A complete
non-starter?
--
Anyway, to expand on the issue a bit, since I was rather vague before:
What's bothering me isn't that the problem can't be solved, but that
I'm struggling to find a way to solve it that's no more painful to
other developers/maintainers than absolutely necessary. None of this
impacts on end-users who use appscript for application scripting as
they never have to instantiate classes directly. But it definitely
affects anyone who has to maintain this code, and it'll very likely
impact on application developers using appscript to implement
application scripting support in their own Python-based applications.
A basic example of the knotty compositions I'm dealing with:
AbstractBase
|
|-- AbstractMid
| |
| |-- Public1
| |
| |-- Public2
|
If I want to complement/extend/replace the behaviour supplied by
AbstractMid, I can't do this directly. Instead, I have to subclass
both Public1 and Public2, then either cut-n-paste the new code into
both of these subclasses, or use MI to create a new AbstractMid2 that
the new classes inherit from in addition to Public1 and Public2.
Now, add in various circular references, e.g. a method in Public1 may
be responsible for creating and returning new instances of Public2,
and vice-versa. I've already got a scheme whereby modules have to
provide their Base superclass with a reference to themselves, so that
ModuleA's version of Public1 returns instances of ModuleA.Public2
while ModuleAPlus's version of Public1 returns instances of
ModuleAPlus.Public2.
Oh, and ModuleA also imports ModuleAPlus so it can refer to its
classes for type-checking purposes.
It all works, but it's already a right old spiderweb and I've yet to
finish ModuleB and ModuleBPlus, which as their names suggest, build
on ModuleA and ModuleAPlus respectively. Plus another layer which'll
go on top of that to enable automatic sanity-checking and
error-reporting. These layers are supposed to make the package much
more flexible and easy to develop with - the A layer provides a
'geek-level' API, the B level extends this with end user-friendly
sugar, and the 'sanity' layer that users of both A and A+B should be
free to add in if they want them.
...
In a prototype-based language that uses delegation [modifiable at
runtime] instead of inheritance [determined at compile-time],
composing new behaviours would be easy: I'd simply duplicate the
original objects then modify the delegation chain to insert a new
AbstractMidPlus object before AbstractMid. It's dead easy to do, and
dead easy to follow. So I'm fair frustrated at how much harder it is
to get the same results in a class-based language, but I've no choice
but to work within these limitations as best I can.
...
It may be that the most practical solution is to replace the concrete
class structure with a bunch of metaclass factories that pump out the
appropriate classes by mixing together the raw base classes on the
spot according to recipes provided by each 'plugin' module. I could
pretty much do away with the whole inheritance tree and just have a
pile of simple, flat abstract base classes that are slapped into
concrete shape purely via multiple inheritance. This shouldn't make
the method resolution order any harder to fathom than it would be
with a deep single-inheritance tree, I don't think. Though metaclass
programming can be more than a little indigestible to many
developers, so it's not a clear winner either.
...
Mostly, I guess I'm trying to find out which approaches give others
the least goosebumps to think about, and which will reduce them to
quivering blobs at the mere thought. Find out which folk think would
be most practical, given their own experiences, and maybe get a few
pointers on how best to arrange the basic framework. Asking not so
much for my benefit as for everyone else's. After all, you folks are
probably the main developer-side market for the beast, so I'd better
make damn sure you'll be happy with it. :)
Many thanks,
has
--
http://freespace.virgin.net/hamish.sanderson/
More information about the Pythonmac-SIG
mailing list