[Zope3-dev] interface conventions: default=_RAISE_ERROR

Barry A. Warsaw barry@zope.com
Wed, 15 May 2002 10:10:34 -0400


>>>>> "FG" == Florent Guillaume <fg@nuxeo.com> writes:

    FG> I am of the opposite opinion. I feel that the simplest method
    FG> should always raise an exception in case of error instead if
    FG> failing "silently". That's what exceptions are for. Otherwise
    FG> you get subtle bugs.

    FG> For that reason I like getattr and dislike get.

    FG> If I want a function that really returns None or something in
    FG> case of error, it's always easy to define a suitable
    FG> try/except.

Of course, I feel that it's always easy to pass in a marker object and
raise an exception if you get back the marker. :)  And my own normal
use patterns mean that what can often be 1 line with get() turns into
4 lines with try/except.

    FG> The only thing I'm not sure about is the speed: does using an
    FG> exception and treating it in the calling function have
    FG> noticable speed differences vs. returning "default" ?

Years ago (circa 1.5.2?) I did some tests with KeyError, has_key(),
and __getitem__() and found that the balance point was at about a hit
rate of 92%.  Meaning, if 92% of your accesses succeed, it was faster
to catch the exception than to do a has_key() test first, because the
exception happened rarely enough.  If fewer than 92% of your accesses
succeeded then it was faster to do a has_key() test first because of
the overhead of the exception machinery.  This led us to adding get()
with a failobj argument so that you could almost always avoid the
exception and you'd get better performance.

I'm sure the exact numbers have changed since then, but I think the
general rule-of-thumb still applies.  The trade-off depends on whether
you think most of your accesses will fail or succeed.

Raising and catching the exception in Python will always be slower
than returning the default.  Think about it: you have to instantiate
the exception class, then you have to do isinstance() tests of all the
base classes until you find a match.

    FG> (And prefer to see "default" spelt "error_value" or "missing"
    FG> to better show the intent.)

I use `failobj' but `missing' would be fine with me.

yin-and-yang-ly y'rs,
-Barry