Soni L. writes:
so, for starters, here's everything I'm worried about.
in one of my libraries (yes this is real code. all of this is taken from stuff I'm deploying.) I have the following piece of code:
def _extract(self, obj): try: yield (self.key, obj[self.key]) except (TypeError, IndexError, KeyError): if not self.skippable: raise exceptions.ValidationError
due to the wide range of supported objects, I can't expect the TypeError to always come from my attempt to index into a set, or the IndexError to always come from my attempt to index into a sequence, or the KeyError to always come from my attempt to index into a mapping. those could very well be coming from a bug in someone's weird sequence/mapping/set implementation. I have no way of knowing!
I hope that exclamation point doesn't mean you think anybody doesn't understand the problem by now. I think most serious programmers have run into "expected" Exceptions masking unexpected errors. What we don't understand is (a) how your proposed fix is supposed to work without a tremendous effort by third parties (and Python itself in the stdlib), (b) if you do presume enormous amounts of effort, what is in it for the third parties, and (c) why doesn't asking the third parties to create finely graduated hierarchies of exceptions do as well (if not better) than the syntax change?
The grungy details:
So as far as I can tell, your analysis above is exactly right. You have no way of knowing, and with the syntax change *you* still will have no way of knowing. You will be dependent on the implementer to tell you, ie, the obj's getter must distinguish between an actual "this key is not in the object" Error, and an implementation bug. You're asking everybody else to consistently distinguish between KeyErrors you think are KeyErrors and KeyErrors you think are actually bugs. I don't see how they can know what you think, and of course if you're right that they are actually bugs, by that very token the relevant developer probably doesn't know they are there!
And I don't think they'll care enough to make the effort even if they are aware of the difference. Because, if they did care, they already can make the effort by using a wider variety of builtin exceptions, or by adding attributes to the exceptions they raise, or deriving subclasses of the various exceptions that might be raised, or of RuntimeError (and they might disagree on what exception *should* be the base exception!) But they don't do any of those very often. And I've seen principled objections to the proliferation of specialized exceptions (sorry, no cite; ignore if you like). I don't recall them clearly but I suppose some of them would apply to this syntax.
"exception spaces" would enable me to say "I want your (operator/function/whatnot) to raise some errors in my space, so I don't confuse them with bugs in your space instead". and they'd get me exactly that.
But how do you say that to me? I'm not your subcontractor, I'm an independent developer. I write a library, I *don't know* what "your" exception spaces are. It's the other way around, I guess? That is, I raise exceptions in *my* space and some in builtin space and maybe even some in imported spaces and you have to catch them explicitly to distinguish. I think you're going to have to do a lot of studying and a lot of extra work on exception handling to catch only the exceptions you intend to. I'm not sure it's going to be worth it to do the necessary research to be able to write
# these are KeyErrors you deem to be the real McCoy except KeyError in SpaceX | SpaceY | SpaceZ: handle_spacey_errors()
# these are exceptions from spaces that you think are probably bugs except KeyError: raise OutDamnSpotError
whenever you're handling potential exceptions from third-party code. And I think you have to do it consistently, because otherwise you may be missing lots of masked bugs. If it's not worth it for *you* to use it *consistently*, why would the tremendous effort imposed on others to lay the foundations for your "occasional" use be worth it?
One of the main points of exceptions as a mechanism is that they "bubble up" until caught. If they occurred deep in the import hierarchy, you may consider that a bug if middle layers don't distinguish, but the developer-in-the-middle may disagree with you if you're handing their library inputs they never intended to handle. I guarantee you lose that argument, unless you are *very* nice to Ms. DITM.
Bottom line: I just don't see how this can work in practice unless we make the "in" clause mandatory, which I suspect is a Python 4.0 compatibility break of Python 3.0 annoyance. I know it would annoy me: my exception handling is almost all of the "terminate processing, discard pending input as possibly corrupt, reinitialize, restart processing" variety. I just don't care about "masked bugs".
it's also backwards compatible.
I don't think so, if it's to be useful to you or anyone else. See discussion preceding "unless we make it mandatory," above.
anyway, I'm gonna keep pushing for this because it's probably the easiest way to retrofix explicit error handling into python,
You're not going to get that, I'm pretty sure, except to the extent that you already have it in the form of Exception subclasses. Python is not intended to make defects hard to inject the way Rust is. (Those are observations, not policy statements. I don't have much if any influence over policy. ;-) I just know a lot about incentives in my professional capacity.)