Exception as the primary error handling mechanism?

r0g aioe.org at technicalbloke.com
Tue Jan 5 04:52:32 EST 2010


Steven D'Aprano wrote:
> On Tue, 05 Jan 2010 02:31:34 +0000, r0g wrote:
> 
>> A pattern I have used a few times is that of returning an explicit
>> success/failure code alongside whatever the function normally returns.
> 
> That doesn't work for languages that can only return a single result, 
> e.g. C or Pascal. You can fake it by creating a struct that contains a 
> flag and the result you want, but that means doubling the number of data 
> types you deal with.


No, but that's why I try not to use languages where you can only return
a single result, I always found that an arbitrary and annoying
constraint to have. I leads to ugly practices like "magic" return values
 in C or explicitly packing things into hashtables like PHP, yuk!


> 
> 
>> While subsequent programmers might not intuit the need to test for
>> (implicit) "magic" return values they ought to notice if they start
>> getting tuples back where they expected scalars...
> 
> What if they're expecting tuples as the result?
> 
> 
> 
>> def foo(x)
>>     if x>0:
>>         return True, x*x
>>     else:
>> 	return False, "Bad value of x in foo:",str(x)
>>
>> ok, value = foo(-1)
> 
> Oops, that gives:
> 
> ValueError: too many values to unpack
> 
> 
> because you've returned three items instead of two. When an idiom is easy 
> to get wrong, it's time to think hard about it.
> 


That seems pretty clear to me, "too many values to unpack", either I've
not given it enough variables to unpack the result into or I've returned
too many things. That would take a couple of seconds to notice and fix.
In fact I was trying to make the point that it would be quite noticable
if a function returned more things than the programmer was expecting,
this illustrates that quite well :)




> 
> 
>> if ok:
>>     print "foo of x is", value
>> else:
>>     print "ERROR:", value
> 
> 
> Whenever I come across a function that returns a flag and a result, I 
> never know whether the flag comes first or second. Should I write:
> 


Flag then result, isn't it obvious? The whole point of returning a flag
AND a result is so you can test the flag so you know what to do with the
result so that implies a natural order. Of course it doesn't matter
technically which way you do it, make a convention and stick to it. If
you get perpetually confused as to the order of parameters then you'd
better avoid this kind of thing, can't say as I've ever had a problem
with it though.




> And I never know if the flag should be interpreted as a success or a 
> failure. Should I write:
> 
> ok, result = foo(x)
> if ok: process(result)
> else: fail()



Yes. That would be my strong preference anyway. Naturally you can do it
the other way round if you like, as long as you document it properly in
your API. As you say different APIs do it differently... Unix has a
convention of returning 0 on no-error but unix has to encapsulate a lot
in that "error code" which is a bit of an anachronism these days. I'd
argue in favour of remaining positive and using names like ok or
success, this is closer to the familiar paradigm of checking a result
does not evaluate to false before using it...

name = ""
if name:
    print name





> And if the flag indicates failure, what should go into result? An error 
> code? An error message? That's impossible for statically-typed languages, 
> unless they have variant records or the function normally returns a 
> string.


Yeah, in my example it's an error message. Maybe I shouldn't have used
the word "pattern" above though as it has overtones of "universally
applicable" which it clearly isn't.



> Again, it's error-prone and messy. Imagine writing:
> 
> 
> flag, a = sin(x)
> if flag:
>     flag, b = sqrt(x)
>     if flag:
<snip>
> Compare that to the way with exceptions:
> 
> y = exp(sin(x) + cos(sqrt(x)))/log(x)
> 
> 
> Which would you prefer?
> 

LOL, straw man is straw!

You know full well I'm not suggesting every function return a flag, that
would be silly. There's no reason returning flag and a value shouldn't
be quite readable and there may be times when it's preferable to raising
an exception.

I use exceptions a lot as they're often the right tool for the job and
they seem pleasingly pythonic but from time to time they can be too slow
or verbose, where's the sense in forcing yourself to use them then?

Roger.



More information about the Python-list mailing list