[Python-3000] PEP 3124 - Overloading, Generic Functions, Interfaces, etc.
Phillip J. Eby
pje at telecommunity.com
Fri May 11 18:29:48 CEST 2007
At 09:46 AM 5/11/2007 -0400, Jim Jewett wrote:
>As much as it seems clear once you understand ... it isn't, if only
>because it is so unexpected. I think it needs an example, such as
> class A: ...
> class B(A): ...
>Then register before/after/around/normal methods for each, and show
>the execution path for a B(). As I understand it now (without
>rereading the PEP)
> AroundB part 1
> AroundA part 1
> # NormalA gets skipped, unless NormalB calls it explicitly
> AroundA part 2
> AroundB part 2
The above is correct, except that either AroundB or AroundA *may*
choose to skip calling the parts they enclose.
>But maybe it would just be AroundB, because an Around is really a replacement?
If AroundB didn't call its next-method, it would indeed be a replacement.
> > >I can see a problem with this. If Library1 defines a
> > >method that always overrides an @around method, and
> > >Library2 does the same thing, then if I try to use
> > >both libraries at the same time, I'll get an exception
> > >that I don't know the cause of and don't have any
> > >idea how to fix.
> > Actually, that would require that Library1 and Library2 both add
> > methods to a generic function in Library3. Not only that, but *those
> > methods would have to apply to the same classes*. So, it's actually
> > a lot harder to create that situation than it sounds.
> > In particular, notice that if Library1 only uses its combinators for
> > methods applying to its own types, and Library2 does the same, they
> > *cannot* create any method ambiguity in the third library's generic
> > functions!
>Library 1 and Library 2 both register Sage classes with Numpy, or vice
>versa. Library 1 and 2 don't know about each other. Library 1 and 2
>also go through some extra version skew pains when Sage starts
>registering its types itself.
Well, all the more reason to have this in place for 3.0 where
everybody is starting over anyway. ;-)
Seriously though, it seems to me that registering third-party types
in fourth-party generic functions, from *library* code (as opposed to
application code) is unwise. I mean, you're already talking about
FOUR people there, *not* counting Library 2! (i.e., Sage, Numpy,
Library 1, and the user).
However, the simple solution is that L1 and L2 should subclass the
relevant Sage types and only register their subclasses. Then, they
each effectively "own" the types, and if Sage registers useful stuff
later, they can just drop their subclasses.
That doesn't eliminate the issue of what type(s) the user of L1 and
L2 should use, unless of course the use of Sage in at least one of L1
and L2 is embedded and not user-visible. However, it's not like such
questions of choice and compatibility don't come up all the time
anyway, and the user could, if he/she had to, use multiple
inheritance plus some additional registrations of their own to work things out.
Also, remember that the user can always resolve ambiguities between
libraries by making additional registrations that more specifically
apply to the situation.
So, can you write a library that messes things up for other
people? Sure! But you can already do that; this ain't Java, and
we're all consenting adults. If you write libraries that mess stuff
up, you're going to get complaints.
The best practice here reminds me of a joke my coworkers used to tell
when I was in the real estate software business. One of our
salespeople was talking to a real estate broker and explaining the
menu of our program:
"See, if your company lists it, and another company sells it, or if
you sell it, that's an "Inside Listing Sold". But if another company
lists it, and *you* sell it, then we call that an "Outside Listing Sold"."
The broker nodded. "But what if another company lists *and* sells it?"
The salesperson thought a moment, then smiled. "Well, we call that,
"None of your business!""
In the same way here, you can register your types with other people's
generic functions, or other people's types with your generic
functions, or even your own types with your own generic
functions. But registering other people's types with other people's
generic functions is what we would politely call, "none of your business". :)
>hmm... if Library 2 is slightly buggy, or makes a slightly different
>mapping than library 1, then my getting correct results will depend on
>which of Library 1/Library 2 gets imported first -- or, rather, first
>got to the registration stage of their being imported.
Note that for "@around" and "@when/@overload", import order *does not
resolve ambiguity*. If the registrations are for the same types,
calling the function with those types will raise an AmbiguousMethods
error that lists the conflicting methods.
But, as I pointed out above, it's a bad idea for those two libraries
to directly register another library's types without subclassing them
first, per the NOYB rule. :)
More information about the Python-3000