3 ms·
With respect to Python, what is the practical difference between: try: something() except FooError as err: raise BazError("something ba
by randomdata 3y ago
With respect to Python, what is the practical difference between:
try:
something()
except FooError as err:
raise BazError("something bad happened", err)
except BarError:
return 1
and
err := something()
switch {
case errors.Is(err, FooError):
return 0, NewBazError("something bad happened", err)
case errors.Is(err, BarError):
return 1, nil
}
? I see no meaningful difference at all.
The only thing that stands out to me is that Go version gets you thinking about errors more (although not as much as some other languages), not being sourced from something bolted onto the side. In Python, you are more likely to lazily call something() blissfully unaware that an error may occur. Is the problem actually not with Go per se, but that people don't want to be reminded that errors are a thing, presumably because they don't want to put in the hard work to properly deal with them?
It is quite true that properly dealing with errors is hard work. Really hard work. But it is also the most important code in your application, so I posit that it is work worth doing.
- JodieBenitez 3y ago> In Python, you are more likely to lazily call something() blissfully unaware that an error may occur. It's not about being lazy or unaware (frankly, that's condescending). No matter the language, IDEs are pretty clear about what errors a something() could trigger. It's not about terseness of the code either. Again, IDEs will just fold all the "if err != nil" blocks so I don't care. It's about separation of concerns. Example: If I develop an app which rely on external resources such as an API or database, there may not be any reason to manage all of their possible failures upfront, right in the middle of the so-called "happy path" of the current business logic. Just let the connection error bubble up and do right thing (ie. rollback whatever you had, log the error and display a nice message to the user, or whatever is needed) elsewhere where this error dealing is centralized along with all http transport shenanigans. That's kinda like the Java checked exception thing: annoying with no real benefit. These days I port an app to Go. And I really like some of the things it brings to the table (mostly unrelated to the language semantics though). But it also feels incredibly archaic at times, error handling not being the only culprit here.
- randomdata 3y ago> there may not be any reason to manage all of their possible failures upfront You still need to handle the errors you receive to ensure that implementation details do not leak to the next caller. That, at very least, means returning (or raising/throwing) a new error that is relevant to the function returning it - not what was relevant to any functions it happened to call. To continue with your example: If your database error bubbles up, callers will come to rely on those error values. Then, when changing requirements sees you need to switch your implementation to a web service API – with a whole different set of errors – now everything they wrote is broken. Which is especially problematic in languages like Go and Python where possible error values are not well communicated to the caller via language constructs. Your code will compile just fine, and seemingly run fine, until that SQL error you were expecting becomes a 500 HTTP error that you didn't know to handle, and now you're in a difficult place. Maybe you can get away with that practice if you have checked exceptions, as at least the compiler will blow up when the possible set of errors change, but it's still a pretty awful API design to leave the caller breaking like that just because you changed an insignificant (to the caller) implementation detail underneath the abstraction they are using. > (frankly, that's condescending) Flawed logic. There is no emotional component to a discussion.