RFC : Try-Catch Blocks

I think you could do something like that (though I'm not sure I find it more readable, question of usage I suppose):

try!(open_file()
    .and_then(|f| f.read_file())
    .and_then(|f| f.write_file())
    .and_then(|f| f.close_file()));

Anyway, I guess it's a matter of taste, but personally I am not a big fan of try/catch blocks and like the way it is in Rust. Yes, in some case it is a bit more verbose, but I prefer to see clearly which parts can file. Compare this (try/catch style):

try {
   let x = f(g(h()));
   do_stuff(x);
} catch (...) {...}

with this (current rust style):

let x = f(try!(g(h())));
try!(do_stuff(x)); 

The latter case is a bit more verbose, but at least you clearly see that if there is an error it is because either or g or do_stuff, whereas in the former case it could be any function called.

What I find frustrating with try! is that when you want to use it in a function that does not return a (compatible) Result, you have to somehow refactor your code (which in some case might actually be a good thing in the long run but anyway).

On the other hand I guess it would be possible to implement some kind of macro which would allow to make "inner try!s" "return" from this macro instead of the function. E.g:

fn main() {  // doesn't return a Result!
  let x = 42;
  catch!(error: SomeError {
    let y = try!(some_stuff(x));
    println!(y);
  } { 
    println!("oops: {}", error.description());
 });
 println!("this will get printed in any case");
}

which would translate to something like:

fn main() {
  let x = 42;
  let closure = move || -> Result(_, SomeError) { 
    let y = try!(some_stuff(x));
    println!(y);
  }
  match closure() {
    Ok(x) => x,
    Err(error) => println!("ooops: {}", error.description());
  }
  println!("this will get printed in any case");
}

At leat, i'm not very well versed in macros (and am not even sure using a closure for that wouldn't cause borrowcheck issues), but I think it should be possible to implement that with a macro. Though honestly I just got this idea but writing it I'm quite dubious it would be useful.

1 Like

hi elizabeth_henry,

thank you for your refreshing post.

I'm looking at your examples, and I can see elegant things. Also I realized earlier exceptions are useless without stacktraces. I had a nice walk earlier, maybe that's all I really needed =)
Everybody was telling me !try is enough, now I'm realizing they are right =)

So this RFC is cancelled then, as there is already an open RFC about it. I'll be happy to see try-catch feature coming in the future. But I can wait, after all.

Rust is awesome! but painful as beginner :smile:

I will only add references to scala handling (so you could see in other lang that also has "proper exceptions"(because they need to interact with java programmers) and is also functional, you could find them also helpful I guess (don't know, still learning rust, still learning scala)

1 Like

Regarding your edit. I dont think that the ?-operator in RFC 243 would be a backwards incompatible change, because it wouldn't break existing code. AFAICS the decission is just postponed. (but I am not a rust developer)

Regarding try catch blocks, I think that you can just use a closure, so they may not be neccesary.

EDIT: I think that discourse strips hashtags in links, so but I wanted to linkto Phauxs comment on march 24

1 Like

I am against try-catch blocks. I do not see how they can offer an ergonomic advantage over the current functional approach.

1 Like

Thank you so much @tyoc213 for these Scala papers, I had a look and it is a very nice language, with a very clean feel. I can see how much it has influenced Rust. Scala is definitely a language to consider, however for the project I'd like to build, I need low-level, cross-platform, native compilation, performance matters a lot on this one.

This is what I figured out, Rust users don't want try-catch blocks.
I've found a great article explaining some of Rust's history on the subject: Don't Panic! The Hitchhiker's Guide to Unwinding | Armin Ronacher's Thoughts and Writings
Very enlightening.

2 Likes

I'm for a way to be able to catch inside a method.

Why ?

Let's say I've a bunch of code in code_block_a which operates on files it created. Every step where it could fail, it needs to delete this bunch of files. Taking this cleanup into a macro would mean having a cleanup call for every try! I'm using there, that would be a real mess.

So a

try {
    //code block A 
} catch {
    //clean up the files
}

would be nice, instead of calling another function just for the sake of doing a final catch on the return value.

fn catcher {
    match code_block_a() {
        Err(e) => cleanup..

and

fn code_block_a -> Result<(),Error> {
    // operate here and return on failure ..
}
1 Like

Wouldn't it be cleaner to clean up files using an object with the Drop trait? Then the compiler would guarantee for you that the files get cleaned up, and you wouldn't need the extra nested function, plus it extends naturally to the case where you only want to clean up the subset of files that you have actually created so far.

Admittedly, I've never done this myself, and am still something of a newbie to rust error handling.

3 Likes

It certainly would look cleaner, but you'd have to be careful not to leak the value then – otherwise the files would never be cleaned up.

@proc yo bro, high five :smile:

@droundy The Drop trait approach is valid only if the cleanup operation is meant to be executed either the operation failed or succeeded. It would act as a finally clause rather than catch. Also It would require a type designed for the operation.

As many mentioned previously, the only option today is to work on some macros or compiler plugin.

My solution was.. to switch to D. I ended up with the conclusion that Rust is not ready yet for large scale, high level projects. So far it is a good alternative to C, yet not C++. Looking forward to next Rust versions.

@raizam Of course, if you can afford a GC, D is a fine language to choose.

I ended up with the conclusion that Rust is not ready yet for large scale, high level projects.

Such as rustc? servo? Piston? Iron? There are many other projects of various sizes and levels. Given this, your conclusion seems a bit premature.

2 Likes

Not if you provide a method on the guard to "disarm" it.

No, you just need a type that'll execute a callback on Drop; like this Defer type.

Also, having spent about half a decade using D, I'd be more inclined to use Rust on a large-scale project than D.

4 Likes

@llogiq, @DanielKeep Thanks for answering my salty comments with good arguments.

I'm not good enough to understand this in depth, but it is inspiring.

I do see what you mean somehow.

Here is what I've just found:

https://doc.rust-lang.org/std/thread/fn.catch_panic.html

Is this... what I was looking for?

1 Like

Absolutely not. That's only for specific use cases, like isolating unwinding when doing ffi.

Error handling in Rust is done with try! and Result and is quite convenient. I wrote a lot about it here: Error Handling in Rust - Andrew Gallant's Blog I recommend giving it a shot with a careful read.

3 Likes

Hey, big +1 for the Defer type! I'd like to see it in a separate crate, so we can use it without code duplication!
That's one of the missing parts (reminds me of defer keyword in Go, but better, as it's typechecked and implemented with the language, which is another sign of how Rust is much more powerful than Go).

crate scopeguard exists, it doesn't do the Option dance like Defer does, but it's the same idea.

Scopeguard implements deref and passes through, because I use it to run a finalizer on an object that I otherwise modify. So the guard owns it and I borrow it.

Edited: The spotlight forced my hand, it now comes with documentation :smile:

1 Like

Good to know about it, thanks!
The problem with discoverability of such small useful crates is poor docs. It's not just scopeguard's problem, there are a lot of crates with just a couple of lines of description, no documentation link, and just one phrase in readme file at best, without even helpful usage examples. So even if you manage to find it somehow, you don't know how to use it, and opt for another, maybe worse crate, but with better docs.

5 Likes

Yes I understand. I just dumped it out since I happened to show it on stackoverflow and got a request to package it :smile:

Perhaps TWIR should have a "crate of the week" section? cc @nasa42

We could have a nomination/voting process similar to QOTW. Otherwise we could do a sticky thread like the "what're you doing this week?"

1 Like