4 ms·
Assume all functions can throw and there is no extra work reading. A function that has no possibility of error is so uninteresting in the context of error handl
by wvenable 4y ago
Assume all functions can throw and there is no extra work reading. A function that has no possibility of error is so uninteresting in the context of error handling.
Furthermore, handling errors has little to do with where the error is actually caused. In general, you can only do two things with errors: log and kill the operation or retry the operation. Neither of these has anything to do with the leaf function 20 items down in the stack that actually made the network call that failed.
- sanderjd 4y agoWhat you're describing here are unchecked exceptions, which Rust has in the form of panic. There are other kinds of errors that can be handled closer to the point where they occur.
- erik_seaberg 4y agoWe have to be deliberate about where we retry, and how quickly. It’s all too easy for layers to create a death ray of n factorial requests.
- nemothekid 4y agoIf I am in the business of writing robust code; then "assuming all functions can throw" means at the very least forcing every function call to be surrounded by a try/catch block? It almost always make sense to handle an error locally if you can; for example if I want to retry the operation (let's say I'm writing a distributed database client), it may make sense for me to retry another node rather than unwinding to the application level that has now lost all context. >A function that has no possibility of error is so uninteresting that focusing on that is the wrong thing. I spend a lot of time debugging errors in code that has 0% chance of failing. It tends to involve a lot of matrix math. This isn't something you can say is universally true especially given all the hype around AI now.
- quietbritishjim 4y ago> It almost always make sense to handle an error locally if you can This is highly presumptuous. I have written many programs that did not need to handle errors locally, and so exception handlers were only at the very top level (or, actually, just below the top-level usually - but the point is that there were generally few and I had flexibility to decide where to put them). Perhaps you and I write very different applications. But the fact remains that the "almost always" in your statement doesn't hold. Alternatively line of reasoning: if this was always true then there would be little point to Rust's ? as it would be so rarely used.
- azov 4y ago> It almost always make sense to handle an error locally if you can Yes, but “if you can” does a lot of heavy lifting here. In most cases you can’t, and this is when Rust’s ? is used.
- wvenable 4y ago> If I am in the business of writing robust code; then "assuming all functions can throw" means at the very least forcing every function call to be surrounded by a try/catch block? No, absolutely not! You only care about errors where you can retry/ignore or log and terminate so you only have try/catch in those areas. So maybe one or two.
- jeroenhd 4y ago"Assume all things can throw" is what I've seen people do in Java code that adds a million try catch wrappers around everything just in case something may go wrong at some point. The end result is either completely unreadable or impossible to figure out. "How do I return fallback data for FooBarService.wiggle()" often ends up in digging through (incomplete, outdated) documentation or with code that breaks unexpectedly, sometimes even in production. Note that Rust has the same issue, any method can panic and allocation may just fail at some point. There are very few ways good ways to handle those problems correctly, which is why this "everything may kill your program" approach is often criticised.
- yetihehe 4y ago> There are very few ways good ways to handle those problems correctly, which is why this "everything may kill your program" approach is often criticised. In Erlang, "everything may kill your program" is typical method of operation, and there should always be some kind of path to reset your state from known good values.
- wvenable 4y agoDon't get me started on Java and checked exceptions. If you don't have checked exceptions, you should not have a million try/catch blocks. In fact, just the opposite. Since you only care about errors when you can retry (or ignore) you should only have a small number of try/catch blocks. Ideally one or none. My best example of this is a UI application that I built that had a single try/catch block around the event loop. It just displayed the error message to the user and returned to the event loop. If they tried to save a file to a network and failed, they got the message, and could just hit save again for somewhere else. No other code needed.
- ModernMech 4y ago> A function that has no possibility of error is so uninteresting that focusing on that is the wrong thing. I disagree, a function that has no possibility of an error is a proper function, and what we need for performance optimized code. Proper functions by definition are just mappings from a domain to a range. That mapping really shouldn’t be predicated on any other state, so it should never fail if the inputs are valid within the domain. We need to focus on such functions if we want performance, because we can only achieve too speeds by not worrying about checking the function result for correctness. Given a proper function, we should just be able to compute the result and move on to the next function. Therefore it’s of great benefit to us (as authors of performant code) to separate our fallible functions from our infallible ones. Keep the fallible ones iutside of hot loops, only infallible ones inside, and that’s a recipe for mechanical sympathy of the sort that results in great performance.