4 ms·
So what do you do when you want centralized error handling, which is the whole point of try-catch idiom? >he second side effect is that it forces you to think
by gambler 8y ago
So what do you do when you want centralized error handling, which is the whole point of try-catch idiom?
>he second side effect is that it forces you to think about how to handle possible errors.
Java does this with throws E and (at least in Java) it sucks and I very much prefer C#'s implicit throws. In fact, I don't think it goes far enough. If you have complex error recovery, the language should allow you to completely separate good executions paths from the bad paths. Scope guards are a step in the right direction.
How would Rust code looks like if the error handling logic was something like "try X, if it fails try again, if that fails schedule another attempt via a queue, log a warning; if scheduling fails log a fatal error"?
Sure, handling this stuff with try-catch looks horrible. But I've thought long an hard about how to simplify it and using tricks like .unwrap_or (which you can simulate in C# to some extent) does not cut it, because error handling often requires to operate on method-scoped variables (e.g. for logging).
- ChrisSD 8y agoDepends what exactly you're looking to do. You can propagate errors with the `?` operator. And you can match on the specific error at a higher level. The docs[0] do give a more complex example of error matching: fn main() { let f = File::open("hello.txt"); let f = match f { Ok(file) => file, Err(error) => match error.kind() { ErrorKind::NotFound => match File::create("hello.txt") { Ok(fc) => fc, Err(e) => panic!("Tried to create file but there was a problem: {:?}", e), }, other_error => panic!("There was a problem opening the file: {:?}", other_error), }, }; } Although they also provide a slightly simpler alternative for this particular case. [0] https://doc.rust-lang.org/stable/book/ch09-02-recoverable-errors-with-result.html https://doc.rust-lang.org/stable/book/ch09-02-recoverable-er...
- gambler 8y agoDoesn't look that much cleaner than try/catch, to be honest. What I would really like to see in C#: public int DoThing(int y) { //logic } catch (SomeException e) { //handle things return 0; } This would remove a lot of useless syntactic garbage without the need for any radical changes in the language. (It would translate to try-catch that wraps the entire body of the method.) But so far I gave up on syntax-level error handling of any complexity. Generally, I just write multiple "agents" and all the error handling, retries and recovery is simply done by separate agent(s). The agent that tries to perform the initial actions simply records that it failed in some persistent storage and terminates or goes on to do something else.
- ilitirit 8y ago> It would translate to try-catch that wraps the entire body of the method It would not not be the same unless you change how scoping works in these instances, and that can introduce other complexities, e.g. how to limit scope so that some things are inaccessible to the catch block.
- gambler 8y agoThis: public void DoThing(){ //code } catch (Exception x){ } finally { } would simply be syntactic sugar for this: public void DoThing(){ try { //code } catch (Exception x){ } finally { } } It's consistent.
- ilitirit 8y agoYes, and that only works by changing how scoping works. Unless of course you don't care about the variables created inside. i.e. public void DoThing() { var someVar = SomeStaticClass.FooFunc(); someVar.DoSomething(); } catch (Exception x) { // Scoping rules will need to change // to put someVar in scope: _logger.Log($"{someVar.GetId()} is invalid"); } finally { someVar.Cleanup(); } And this also implies that there's no way to make a variable declared inside the method inaccessible to the catch block without additional changes to the language.
- gambler 8y ago>Unless of course you don't care about the variables created inside. In majority of cases I really don't care about the variables created inside. If I can't handle an error just by looking at the exception and method arguments I usually refactor. In my view, error handling should not be intertwined with the "happy path". It makes reasoning about non-trivial code much harder. For other cases the old syntax will still be available. And yes, the value of "finally" in such a shorthand is dubious. I just added it to make it clear how the rewrite rule would work.