Exception as the primary error handling mechanism?
Steven D'Aprano
steven at REMOVE.THIS.cybersource.com.au
Tue Jan 5 03:26:10 EST 2010
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.
> 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.
> 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, result = foo(x)
or
result, flag = foo(x)
I've seen APIs that do both.
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()
or
err, result = foo(x)
if err: fail()
else: process(result)
Again, I've seen APIs that do both.
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.
And even if you dismiss all those concerns, it still hurts readability by
obfuscating the code. Consider somebody who wants to do this:
result = foo(bar(x))
but instead has to do this:
flag, result = bar(x)
if flag: # I think this means success
flag, result = foo(x) # oops, I meant result
Again, it's error-prone and messy. Imagine writing:
flag, a = sin(x)
if flag:
flag, b = sqrt(x)
if flag:
flag, c = cos(b)
if flag:
flag, d = exp(a + c)
if flag:
flag, e = log(x)
if flag:
# Finally, the result we want!!!
flag, y = d/e
if not flag:
fail(y)
else:
fail(e)
else:
fail(d)
else:
fail(c)
else:
fail(b)
else:
fail(a)
Compare that to the way with exceptions:
y = exp(sin(x) + cos(sqrt(x)))/log(x)
Which would you prefer?
--
Steven
More information about the Python-list
mailing list