How about "pure virtual methods"?

Alex Martelli aleaxit at yahoo.com
Sun Dec 19 16:42:06 EST 2004


Fredrik Lundh <fredrik at pythonware.com> wrote:
   ...
> Alex Martelli wrote:
> 
> >>     Traceback (most recent call last):
> >>     File "mymodule.py", line 9, in somefunction
> >>         someobj.bar()
> >>         ... zero or more lines ...
> >>     File "somelibrary.py", line 3, in bar
> >>         raise NotImplementedError("must implement abstract method bar")
> >>     NotImplementedError: must implement abstract method bar
> >>
> >> you have to look at the last line of a traceback to find the error
> >> message, and the offending module/method is two lines above that.
> >
> > The offending module is the one which instantiates a class it shouldn't
> > instantiate -- a class which isn't made concrete by overriding all
> > methods which need to be.  What is that module?
> 
> in real life, it's mymodule.py or mylib.py, in code that you wrote very
> recently.

In my experience, it ain't necessarily so.  Maybe I happen to work more
than you do with, for example, people who've had indoctrination into
"the proper ways to do OOP" (meaning C++ or Java) -- indeed I've found
that wanting to make abstract classes with methods which raise
exceptions, rather than just omitting the methods (and thus getting an
AttributeError if anybody tries calling them on instances of subclasses
which lack them) has a good correlation with people with the mindset
typically coming from such doctrine.

Such people write modules which define abstract classes and also the
functions that receive instances of such abstract classes (sometimes
they even check for that with isinstance!) and call methods on them --
never, in practice, will the same 'mymodule.py' that calls someobj.bar()
be the one which created 'someobj'; rather 'someobj' will be an argument
to 'somefunction' -- so you need to continue the study up the stack of
calls.  I'm not saying "it can't be done"!  I'm saying it's quite likely
to take EXTRA MINUTES (that's ALL I'm claiming, remember: so, your
counterclaim is that such a search *hardly ever takes more than an extra
119 seconds*!!!) to find out where the should-be-concrete class is
defined and instantiated, starting from the first call to one method it
has wrongfully left un-overridden, compared to the case where the class
statement itself, or the instantiation, raise the exception.

As for the "code you've written recently": maybe, IF that abstract class
and supporting infrastructure never changes.  If your application-level
code uses frameworks which change (never a pleasant situation, but it
does often happen), then it's quite likely the *framework* has changed
recently, adding a deuced new 'bar' method that now you're supposed to
override, too.  Again, you must find out where you defined the subclass
which happens to be the class of 'someobj'.  Again, I would NOT be
surprised if it took 121, even 122 seconds... or (gasp!) occasionally
even more!


> > The error is generally not the calling of 'bar' on someobj: someobj
> > arrives as a argument to somefunction from somewhere -- the caller of
> > somefunction is quite often innocent, in turn -- who BUILT someobj, by
> > instantiating which class?  I think `minutes' is a very fair (not at all
> > pessimistic) assessment of the time it will generally take to find out.
> 
> you can blather for years if you want to, but your arguments are just
> another variant of the "you cannot use whitespace for indentation" stuff
> we've all seen from time to

I'm not saying you *cannot* do anything: I'm claiming that, if you do
things in a slightly different way, it will often save you 120 or more
seconds of time in finding out where you made a mistake.

If you think it's worth the bother of putting in 'empty' abstract
methods which raise NotImplementedException (rather than saving the time
in the first place by just omitting them), you must be convinced they
help productivity -- e.g. make it faster to find errors, compared to the
easier-to-obtain effect of getting an AttributeError.  How?  And how
comes a more precise indication of where the override was not done
(ideally by raising at the class statement, but instantiation time isn't
all that much worse) appears in your opinion to give NO further added
value, not even two minutes' worth?

> time; it's trivial to come up with a large number of theoretical problems
> with any given approach, but in real life, for real-life programmers,
> using real-life libraries designed by real-life developers, it's simply
> not the problem you want it to be.

I don't "want" anything in particular.  I _have_ observed people
spending over 120 seconds finding out where the errant class was defined
and what methods it was missing -- with real-life everythings; just the
same amount of time they'd have spent without the silly
NotImplementedError to "help", just by reasoning from AttributeError.

 
> but not that I'm going to convince you, now that you've spent 15,000
> characters on this topic...

Characters are cheap.  On the other hand, I can't see how you can
convince me that what I've observed (and common sense confirms) is an
illusion, that one can't waste two minutes finding exactly where the
errant class was defined.  Since it takes about 4 minutes to code that
metaclass, if twice in a project's lifetime, 2 minutes each time are
saved, one breaks even; if three times, one's gaining.  This doesn't
take into account the large amount of times wasted on this incredibly
silly thread, of course, but hey, I disclaim any responsibility for it:
I posted a sketch of a dozen lines of code to solve a real-life problem
somebody seemed to be having, and found myself unexpectedly under attack
for 'posting a magnum opus', 'blathering for years', and now even
arguing against using whitespace for indentation.

Definitely not the c.l.py I recalled; if that's what one can expect,
these days, for posting a dozen lines of HTH code -- amount of thanks or
any expression of gratitude a nice round zero, amount of flames and
direct attacks as high as I've gotten so far -- I guess I'm not going to
stay around all that long this time.


Alex



More information about the Python-list mailing list