On 2020-04-10 2:24 p.m., Andrew Barnert wrote:
On Apr 10, 2020, at 06:00, Soni L. email@example.com wrote
why's a "help us fix bugs related to exception handling" proposal getting so much pushback? I don't understand.
Because it’s a proposal for a significant change to the language semantics that includes a change to the syntax, which is a very high bar to pass. Even for smaller changes that can be done purely in the library, the presumption is always conservative, but the higher the bar, the more pushback.
There are also ways your proposal could be better. You don’t have a specific real life example. Your toy example doesn’t look like a real problem, and the fix makes it less readable and less pythonic. Your general rationale is that it won’t fix anything but it might make it possible for frameworks to fix problems that you insist exist but haven’t shown us—which is not a matter of “why should anyone trust you that they exist?”, but of “how can anyone evaluate how good the fix is without seeing them?” But most of this is stuff you could solve now, by answering the questions people are asking you. Sure, some of it is stuff you could have anticipated and answered preemptively, but even a perfectly thought-out and perfectly formed proposal will get pushback; it’s just more likely to survive it.
If you’re worried that it’s personal, that people are pushing back because it comes from you and you’ve recently proposed a whole slew of radical half-baked ideas that all failed to get very far, or that your tone doesn’t fit the style or the Python community, or whatever, I don’t think so. Look at the proposal to change variable deletion time—that’s gotten a ton of pushback, and it’s certainly not because nobody respects Guido or nobody likes him.
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
(A Boneless Datastructure Language :: abdl._vm:84-89, AGPLv3-licensed, https://ganarchy.autistic.space/project/0f74bd87a23b515b45da7e6f5d9cc8238044... @ 34551d96ce021d2264094a4941ef15a64224d195)
this library handles all sorts of arbitrary objects - dicts, sets, lists, defaultdicts, wrappers that are registered with collections.abc.Sequence/Mapping/Set, self-referential data structures, and whatnot. (and btw can we get the ability to index into a set to get the originally inserted element yet) - which means I need to treat all sorts of potential errors as errors. however, sometimes those aren't errors, but intended flow control, such as when your program's config has an integer list in the "username" field. in that case, I raise a ValidationError, and you handle it, and we're all good. (or sometimes you want to skip that entry altogether but anyway.)
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 also don't have a good way of changing this to wrap stuff in RuntimeError, unfortunately. (and yes, this can be mitigated by encouraging the library user to write unit tests and integration tests and whatnot... which is easier said than done. and that won't necessarily catch these bugs, either. (ugh so many times I've had to debug ABDL just going into an infinite loop somewhere because I got the parser wrong >.< unit tests didn't help me there, but anyway...))
"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. it's basically a hybrid of exceptions and explicit error handling. all the drawbacks of exceptions, with all the benefits of explicit error handling. which does make it worse than both tbh. it's also backwards compatible. I'm trying to come up with a way to explain how "exception spaces" relate to things like rust's .unwrap() on an Result::Err, or nesting a Result in a Result so the caller has to deal with it instead of you, or whatnot, but uh this is surprisingly difficult without mentioning rust code. but think of this like inverted rust errors - while in rust you handle the errors in a return value, with my proposal you'd handle the errors by passing in an argument. or a global. or hidden state. anyway, this is unfortunately more powerful.
my "toy example" (the one involving my use-case, not the one trying to define the semantics of these "exception spaces") is also real code. (GAnarchy :: ganarchy.config:183-201, AGPLv3-licensed, https://ganarchy.autistic.space/project/385e734a52e13949a7a5c71827f6de920dbf... @ not yet committed) it's just... it doesn't quite hit this issue like ABDL, template engines, and other things doing more complex things do. I'm sorry I don't have better examples, but this isn't the first time I worry my code is gonna mask bugs. it's not gonna be the last, either.
anyway, I'm gonna keep pushing for this because it's probably the easiest way to retrofix explicit error handling into python, while not being as ugly and limiting as wrapping everything in RuntimeError like I proposed previously. (that *was* a bad proposal, tbh. sorry.) I'll do my best to keep adding more and more real code to this thread showing examples where current exception handling isn't quite good enough and risks masking bugs, as I notice them. which probably means only my own code, but oh well.