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/

Reply via email to