Live data from Hacker News

My philosophy of exceptions: they're always ambiguous (2021)

adamhooper.medium.com

41–46 of 46 posts

Re: My philosophy of exceptions: they're always ambiguous (2021)

#41
post #37
post #16

> Python, C++, Ruby and Java all use exceptions. To them, “exception” means, “nifty piece of syntax kinda like goto.” Not Ruby. In idiomatic Ruby^ exceptions are for exceptional cases, not code flow. "nifty piece of syntax kinda like goto." is the much underused but very powerful catch+throw. Or rather, it's a stack unwinding mechanism: think baseball, the catcher expects a ball, with the ball being a message to be p…

[1]: isinstance(StopIteration, Exception) [1]: False

yeah.. StopIteration is not an instance of Exception, is a subclass of it :^)

no, really:

   help(StopIteration)

   class StopIteration(Exception)
    |  Signal the end from iterator.__next__().
    |  
    |  Method resolution order:
    |      StopIteration
    |      Exception
    |      BaseException
    |      object
...

Re: My philosophy of exceptions: they're always ambiguous (2021)

#42

Earlier quoted context omitted.

The main problem I have with exceptions is that libraries can't be trusted to only throw exceptions in exceptional situations, or even properly document the situations in which they throw exceptions, so my code must be constantly paranoid about every call into library code. Contrast this with languages that provide result types and the certainty of either handling or passing up the error, particularly when the langua…

I just assume every piece of code can throw any kind of exception. If some code doesn't throw an exception today, it might change tomorrow. It ultimately doesn't matter. There is no need to worry about it. There are only key points in any application where you can properly handle errors/exceptions and only certain errors/exceptions that can be handled in a specific way. Neither the location of the handler or can be h…

I disagree with most of your arguments. I think that exceptions are obviously part of the API - they just tend to be a lot more hidden and less thoughtfully designed than the standard interface.

Wrapping or mapping internal exceptions to a API level library-specific type isn't lying, it's just basic data modelling - the same as mapping e.g., a database response to a HTTP response, including database errors to client-appropriate HTTP error codes

And error handling can and should frequently be managed at the call site into a library, even for exceptional cases. Consider transient errors like network failures - it's standard to handle and retry at the call site with a delay rather than immediately propagate to the caller.

All of this is made simpler and more explicit with the use of Result types or similar over Exceptions.

Fundamentally, I think Exceptions don't simplify anything, they just hide complexity - and Result types don't complicate code, they just describe the otherwise hidden complexity.

Re: My philosophy of exceptions: they're always ambiguous (2021)

#43

Earlier quoted context omitted.

I just assume every piece of code can throw any kind of exception. If some code doesn't throw an exception today, it might change tomorrow. It ultimately doesn't matter. There is no need to worry about it. There are only key points in any application where you can properly handle errors/exceptions and only certain errors/exceptions that can be handled in a specific way. Neither the location of the handler or can be h…

I disagree with most of your arguments. I think that exceptions are obviously part of the API - they just tend to be a lot more hidden and less thoughtfully designed than the standard interface. Wrapping or mapping internal exceptions to a API level library-specific type isn't lying, it's just basic data modelling - the same as mapping e.g., a database response to a HTTP response, including database errors to client-…

I disagree because the complexity doesn't exist. If you concentrate only on the places you can handle errors/exceptions and what you can handle that is significantly simpler than fussing over the individual error return types of every single function call everywhere. That's just a make-work project. The big advantage of exceptions is that you can mostly ignore all that noise.

The fact that some function somewhere can trigger a network exception has nothing to do with where I can handle it and do the retry. Even network failures are rarely handled at the specific exact function that calls the operating system to put a byte on the wire. It's probably at least 5 levels up before it even gets to my code.

Exceptions and properly using Result types are effectively equivalent. Add checked exceptions and they are almost exactly equivalent. But that misses forest for the trees.

Re: My philosophy of exceptions: they're always ambiguous (2021)

#44
post #32

Earlier quoted context omitted.

The code that catches an exception can continue, but the point was about the code that threw the exception. You throw an exception if you can't continue the work you're currently doing, for whatever reason. Of course, the rest of the program can very well continue: some other part will catch the exception you threw and decide what to do next. Ending the entire process is an extreme case, that should be reserved for o…

> Also, there is little fundamentally different between throwing an exception and returning an error result. Thank you. I was about to reply the same. The most notable difference is that from a usage-perspective is that exceptions bubble up automatically, whereas errors must be returned manually. I usually don't follow the error vs. exception debate because both have their difficulties and both let's you write code t…

Why is that more yuck than Option?

Re: My philosophy of exceptions: they're always ambiguous (2021)

#45

Earlier quoted context omitted.

I disagree with most of your arguments. I think that exceptions are obviously part of the API - they just tend to be a lot more hidden and less thoughtfully designed than the standard interface. Wrapping or mapping internal exceptions to a API level library-specific type isn't lying, it's just basic data modelling - the same as mapping e.g., a database response to a HTTP response, including database errors to client-…

I disagree because the complexity doesn't exist. If you concentrate only on the places you can handle errors/exceptions and what you can handle that is significantly simpler than fussing over the individual error return types of every single function call everywhere. That's just a make-work project. The big advantage of exceptions is that you can mostly ignore all that noise. The fact that some function somewhere can…

> fussing over the individual error return types of every single function call everywhere. That's just a make-work project

Yep, it's a lot of work. But if you don't do that work of defining a behavior for every error, you create undefined behavior.

Undefined behavior is acceptable in some places (e.g., desktop apps; small web services); it isn't acceptable in other places (e.g., big web services). At scale, you have to know what happens for all inputs. In my experience, this is easier to do if you figure out the error hierarchy ahead of time.

I am the original article author. I was writing after authoring a new RabbitMQ client. Existing clients were throwing exceptions in the wrong places, leading to website stalls. Stalls happened in every client library I could find. The trick is that the RabbitMQ protocol behaves like an actor system: error messages aren't always tied to requests. It took careful error design to map server messages to exceptions, and that error design had to happen at the very start of the project.

Abstracting a bit from that experience:

* exceptions are "error + goto". The goto saves work 99% of the time; the other 1%, it's awful.

* a robust library enumerates all its errors.

Re: My philosophy of exceptions: they're always ambiguous (2021)

#46

Earlier quoted context omitted.

I disagree because the complexity doesn't exist. If you concentrate only on the places you can handle errors/exceptions and what you can handle that is significantly simpler than fussing over the individual error return types of every single function call everywhere. That's just a make-work project. The big advantage of exceptions is that you can mostly ignore all that noise. The fact that some function somewhere can…

> fussing over the individual error return types of every single function call everywhere. That's just a make-work project Yep, it's a lot of work. But if you don't do that work of defining a behavior for every error, you create undefined behavior. Undefined behavior is acceptable in some places (e.g., desktop apps; small web services); it isn't acceptable in other places (e.g., big web services). At scale, you have…

I believe that there are exceptions to every rule :). I'm not going to argue with your experience with RabbitMQ and your solution is probably totally correct. But I think making that a general rule is a mistake. I write all kinds of software from web applications, libraries, desktop applications, and even embedded software and there is no one single right way to do error handling. However, 99% of the time, think exceptions with a very small number of catch blocks is easiest, cleanest, and most robust way to go.

I don't believe exceptions create undefined behavior -- the behavior is very much defined. I know exactly how all my apps will react to exceptions I've seen and not seen. I also know exactly where those exceptions will be handled. I'm also very comfortable knowing that there is no error situation that will be not caught and dealt with in some way. I'd like to know why you think differently?

I think the exceptions are a goto has already been debunked enough. Whether you use exceptions or not, your errors will be handled in the same place in the code. It's just one place you're wasting effort manually propagating that error to that same place and in the other you are not.

Post reply on HN