4 ms·
That is also true of most languages. Java (and Javascript in its attempt to copy it) are about the only languages that actually promote using exceptions for err
by randomdata 5y ago
That is also true of most languages. Java (and Javascript in its attempt to copy it) are about the only languages that actually promote using exceptions for errors, and in hindsight I think we can agree it was a poor design decision. That doesn't stop people from trying to overload exceptions in other languages, Go included, but in terms of what is idiomatic...
However, the question was asking what is different about errors compared to other values. The add function above contains an error, yet I don't know of any language in existence where you would expect a stack trace bundled alongside the result to help you debug it. Why would that need change just because you decided to return a struct instead of an int? And actually, many APIs in the wild do represent errors as integers.
- dragonwriter 5y ago> Java (and Javascript in its attempt to copy it) are about the only languages that actually promote using exceptions for errors Python does. Ruby does. It's not just Java and JS. Go is very open about its approach being a departure. > And actually, many APIs in the wild do represent errors as integers. Many, many APIs in the wild are implemented in (or meant to be consumed from) C, which doesn't even have exceptions, so not using exceptions makes sense for them. Very often idiomatic non-C host language wrappers for those APIs will fire exceptions when they get an error return.
- randomdata 5y ago> Ruby does. Definitely not. Especially because early Ruby implementations brought huge overhead when exceptions were used, you were strongly advised to only use exceptions for actual exceptions. Ruby was one of the first languages that really started pushing the idea that exceptions should be reserved for exceptions, even if was just for technical reasons. Those overhead problems have been addressed and are no longer a problem, but the sentiment has continued to ring true. I agree that doesn't stop people from trying to overload them, as I said earlier. But idiomatic? Not at all.
- rezonant 5y agoRuby has two kinds of exception handling. There is try/catch, this is used for flow control and should not be used for error handling (it doesn't have stack traces). And then there is raise/rescue. Using try/catch as intended is a bit of an art, but raise/rescue is everywhere. It is absolutely the primary way of handling errors. I think you might be confusing these two.
- kortex 5y ago> Python does And it's awful. I use EAFP locally (to avoid TOCTOU and the like) at low level interfaces but I don't let it bubble up out of a function scope, because it is a goto in all but name. I've also been increasingly using the `result` library/data structure. It's incredibly liberating to return an error as an object you can compose into other functions, vs try/catch, which does not compose. Yes I write python almost like rust, and it's great. Strong types, interfaces, immutable types. It looks nothing like "old school python" but also behaves nothing like it. Gone are the day of "oh it crashed again, fix one line and rerun". Exceptions should be for exceptional circumstances, not errors. Edit: I see this is controversial. What do you take objection to? Making your python look less dynamic and more like rust? Try it before you knock it. Python's my favorite language, but I do not agree that many of the common "pythonic" patterns are good at scale. https://returns.readthedocs.io/en/latest/pages/result.html https://returns.readthedocs.io/en/latest/pages/result.html
- eru 5y agoI find, that the problem with exceptions in Python is not so much that it is a goto, but that they are a bit like dynamic scoping (vs static scoping of variables), so you can not reason about them statically. An example: suppose you have a function that does some work with the filesystem, and also calls some user-supplied code. (Perhaps because the user can subclass something etc, or because you are getting a callback, the details don't matter.) Naturally your function might have some idea how to handle its own filesystem trouble, but you have no clue how to handle any filesystem exceptions that come from user provided code. It's rather awkward to get this exactly right.
- Karunamon 5y agoMaybe I'm just too inexperienced, but I don't see the point of this library. The linked example shows a really basic sqlalchemy model lookup. What does spewing these new types all over my code get me that returning None or an empty dict/list doesn't without the overhead? def find_user(user_id: int) -> Optional[User]: user = User.objects.filter(id=user_id) if user.exists(): return user[0] else: return None Not only is this idiomatic, it conveys the same semantic meaning. I'm using an IDE, as is anyone else working in a large codebase. I'll be told at the point of invocation that find_user could return None and I need to possibly deal with that.