To throw or to throw not?

E

Emanuele D'Arrigo

I'm pondering on what is a bit of a philosophical dilemma.
When should I throw an exception and when should I not?

Suppose I have myFunc1() calling myFunc2() which in turn calls myFunc3
().
Suppose myFunc3() has detected a problem. What should it do?

Throw an exception, forcing myFunc2() to handle it and/or trigger
another exception for myFunc1() to deal with? Or should it simply
return a meaningful error code, for myFunc2() and myFunc1() to handle
as an option but not forcing them to do so?

Manu
 
C

Chris Rebert

I'm pondering on what is a bit of a philosophical dilemma.
When should I throw an exception and when should I not?

Suppose I have myFunc1() calling myFunc2() which in turn calls myFunc3
().
Suppose myFunc3() has detected a problem. What should it do?

Throw an exception, forcing myFunc2() to handle it and/or trigger
another exception for myFunc1() to deal with? Or should it simply
return a meaningful error code, for myFunc2() and myFunc1() to handle
as an option but not forcing them to do so?

Depends on how serious the error is (e.g. str.find() returns -1 rather
than raising an exception if it can't find the substring), but 98% of
the time, you'll want to raise an exception; it's Pythonic, idiomatic,
and expected. You'd have to have a *really* good reason to use an
error value/code instead.
Python is not C, and despite what Joel has said On Software, error
codes generally suck.

Cheers,
Chris
 
M

Mensanator

I'm pondering on what is a bit of a philosophical dilemma.
When should I throw an exception and when should I not?

Suppose I have myFunc1() calling myFunc2() which in turn calls myFunc3
().
Suppose myFunc3() has detected a problem. What should it do?

Throw an exception, forcing myFunc2() to handle it and/or trigger
another exception for myFunc1() to deal with? Or should it simply
return a meaningful error code, for myFunc2() and myFunc1() to handle
as an option but not forcing them to do so?

That depends on the situation, doesn't it?

For example, if I want to solve a linear congruence

X*a == Z (mod Y)

all I have to do is check that GCD(X,Y) divides Z and
I can go ahead and call the solving function...

....which requires use of the modular inverse function
which raises an exception if GCD(X,Y) is not 1 (even if
it does divide Z).

But wait! If, in fact, the GCD(X,Y)>1, and I already know
that GCD(X,Y) divides Z, then it divides X, Y and Z, so
I just divide each by GCD(X,Y) to make a new linear
congruence where the modular inverse function will work
and I'll get the right answer.

The answer is that IF the exception can be handled without
the calling function needing to know, then just handle it.
Otherwise pass it back in case the calling function can
figure out what to do.
 
S

Steve Holden

Emanuele said:
I'm pondering on what is a bit of a philosophical dilemma.
When should I throw an exception and when should I not?

Suppose I have myFunc1() calling myFunc2() which in turn calls myFunc3
().
Suppose myFunc3() has detected a problem. What should it do?

Throw an exception, forcing myFunc2() to handle it and/or trigger
another exception for myFunc1() to deal with? Or should it simply
return a meaningful error code, for myFunc2() and myFunc1() to handle
as an option but not forcing them to do so?
Remember that with exceptions, if Func2 doesn't want to process the
exception it doesn't have to do anything at all to have the exception
re-raised: it simply doesn't trap the exception.

regards
Steve
 
S

Steven D'Aprano

I'm pondering on what is a bit of a philosophical dilemma. When should I
throw an exception and when should I not?

Suppose I have myFunc1() calling myFunc2() which in turn calls myFunc3
().
Suppose myFunc3() has detected a problem. What should it do?

Throw an exception, forcing myFunc2() to handle it and/or trigger
another exception for myFunc1() to deal with? Or should it simply return
a meaningful error code, for myFunc2() and myFunc1() to handle as an
option but not forcing them to do so?

In general, you should raise an exception. Then if myFunc2() can't handle
it, it doesn't need to trigger another exception, the exception will just
propagate up the call chain to myFunc1().

There are cases where something like a meaningful error value is
appropriate, but the only one I can think of right now is NaN in floating
point maths.
 
A

Aaron Brady

In general, you should raise an exception. Then if myFunc2() can't handle
it, it doesn't need to trigger another exception, the exception will just
propagate up the call chain to myFunc1().

There are cases where something like a meaningful error value is
appropriate, but the only one I can think of right now is NaN in floating
point maths.

If you need error flags, define them in a class:

class ErrFlags:
onlyInCorner= object( )
livesOnCeiling= object( )

def myFunc3( ):
something( )
return ErrFlags.onlyInCorner

def myFunc2( ):
result= myFunc3( )
if result is ErrFlags.onlyInCorder:
something
elif result is ErrFlags.livesOnCeiling:
something

In some cases, you might want to call a method on the return object.

I agree with the fellows earlier. Without further information,
exceptions are generally nice and solid.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top