On 5/2/2020 7:18 AM, Alex Hall wrote:
On Sat, May 2, 2020 at 12:39 PM Henk-Jaap Wagenaar
<wagenaarhenkj...@gmail.com <mailto:wagenaarhenkj...@gmail.com>> wrote:
Of course, there are other ways of writing this code, but imagine
this for a database interface where a save normally returns the
saved object (inspired by Django)
```
try:
x, y = Foo.save()
except ValueUnpackingError:
// oh... this means saving failed (it returned None instead)
// let's return a sensible response
return ExceptionToResponse(FooStateToException(foo.state))
```
My concern is that this is risky code. If `Foo.save()` has a bug
somewhere inside (or maybe it calls back to your own code which has a
bug) it could raise `ValueUnpackingError` for different reasons, and
then that gets caught and misleads people into thinking that Foo.save
returned None which leads to all sorts of frustration and confusion.
This code:
```
result = Foo.save()
if result is None:
return ExceptionToResponse(...)
x, y = result
```
is not sexy, but it's explicit, safe, and it targets the real problem
precisely.
Creating these new exceptions would encourage people to write code
that will bite them later.
I agree that we don't want to encourage code like the above example with
catching the hypothetical ValueUnpackingError. I contend that even if we
added ValueUnpackingError, no one would ever write code that used it,
but should instead do what they do now: unpack it after checking it (as
Alex's example shows). Of course, that's a horrible API, but sometimes
you have to call horrible APIs. The fact that the API is bad doesn't
mean we should add a way to handle it poorly.
The only reason I'd want it to exist (and I don't) is to see it in the
REPL. But for that, there's the exception message and the traceback, so
a unique exception for this would be useless to me.
Another example would be an interactive session where you expect
an iterable to have 3 entries (say for a 3D space coordinate) and
you want to check this specifically:
```
try:
x, y, z = point
except ValueUnpackingError:
print(f"point has wrong dimension")
```
where point is an instance of:
```
class Point:
def __iter__(self):
return (float(x) for x in self._internal)
```
The first example made sense, this is too much of a contrived toy
example. Why would you write that try/except in an interactive
session? How does catching the exception leave you better off than
just letting it bubble up and show you a traceback? What are you going
to do after now that x,y,z are undefined variables? How did you end up
with a point of unknown dimension?
Can you spot here why ValueError would result in
significantly different behaviour? ValueError will also catch it
if point's internal list contains a bad entry (e.g. a string that
does not convert to a float).
I've never caught an exception in the REPL. And even if I wanted to,
like the other examples above, you'd want to put the exception around
the smallest possible piece of code. What if the each "x" above was an
instance of something whose __float__() might raise ValueUnpackingError?
class X:
def __float__(self):
a, b = [3.0]
return a
You'd be catching a ValueUnpackingError, but the wrong one. Just adding
ever finer-grained exception classes doesn't solve any of the problems
I've seen given in this thread. That's not to say improvement is
impossible, but it will need to be on a case-by-case basis, with
examples that show an actual improvement.
Eric
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/python-ideas@python.org/message/7K6O6Z3OTXTTO52SBZLFT3H6SIKUUX7D/
Code of Conduct: http://python.org/psf/codeofconduct/