Tracking issue for `?` operator and `try` blocks (RFC 243, `question_mark` & `try_blocks` features)
Tracking issue for rust-lang/rfcs#243 and rust-lang/rfcs#1859.
Implementation concerns:
- [x]
?operator that is roughly equivalent totry!- #31954 - [x]
try { ... }expression - https://github.com/rust-lang/rust/issues/39849- [x] resolve
do catch { ... }syntax question- Resolved as
try { .. }, - https://github.com/rust-lang/rust/issues/50412
- Resolved as
- [x] resolve whether catch blocks should "wrap" result value (first addressed in https://github.com/rust-lang/rust/issues/41414, now being settled anew in https://github.com/rust-lang/rust/issues/70941)
- [ ] Add a test confirming that it's an
ExprWithBlock, so works in a match arm without a comma - [ ] Address issues with type inference (
try { expr? }?currently requires an explicit type annotation somewhere).
- [x] resolve
- [x] settle design of the
Trytrait (https://github.com/rust-lang/rfcs/pull/1859)- [x] implement new
Trytrait (in place ofCarrier) and convert?to use it (https://github.com/rust-lang/rust/pull/42275) - [x] add impls for
Optionand so forth, and a suitable family of tests (https://github.com/rust-lang/rust/pull/42526) - [x] improve error messages as described in the RFC (https://github.com/rust-lang/rust/issues/35946)
- [x] implement new
- [x] reserve
tryin new edition - [x] block
try{}catch(or other following idents) to leave design space open for the future, and point people to how to do what they want withmatchinstead
The accompanying RFC discusses a desugaring based on labeled return/break, are we getting that too or will there just be special treatment for ? and catch in the compiler?
EDIT: I think labeled return/break is an excellent idea separate from ? and catch, so if the answer is no I will probably open a separate RFC for it.
Labeled return/break is purely for explanatory purposes.
On Fri, Feb 5, 2016 at 3:56 PM, Jonathan Reem [email protected] wrote:
The accompanying RFC discusses a desugaring based on labeled return/break, are we getting that too or will there just be special treatment for ? and catch in the compiler?
— Reply to this email directly or view it on GitHub https://github.com/rust-lang/rust/issues/31436#issuecomment-180551605.
Another unresolved question we have to resolve before stabilizing is what the contract which impls of Into have to obey should be -- or whether Into is even the right trait to use for the error-upcasting here. (Perhaps this should be another checklist item?)
@reem
I think labeled return/break is an excellent idea ... I will probably open a separate RFC for it.
Please do!
On the subject of the Carrier trait, here is a gist example of such a trait I wrote back early in the RFC process.
https://gist.github.com/thepowersgang/f0de63db1746114266d3
How this is treated during parsing?
struct catch {
a: u8
}
fn main() {
let b = 10;
catch { a: b } // struct literal or catch expression with type ascription inside?
}
@petrochenkov Well, the definition couldn't affect parsing, but I think we still have a lookahead rule, based on the second token after {, : in this case, so it should still be parsed as a struct literal.
Also
let c1 = catch { a: 10 };
let c2 = catch { ..c1 }; // <--
struct catch {}
let c3 = catch {}; // <--
+ https://github.com/rust-lang/rfcs/issues/306 if (when!) implemented. It seems like there are no conflicts besides struct literals.
Given the examples above I'm for the simplest solution (as usual) - always treat catch { in expression positions as start of a catch block. Nobody calls their structures catch anyway.
It would be easier if a keyword was used instead of catch.
This is the keywords list: http://doc.rust-lang.org/nightly/grammar.html#keywords
@bluss yeah, I admit none of them are great... override seems like the only one that is close. Or we could use do, heh. Or a combination, though I don't see any great ones immediately. do catch?
do is the only one that seems to be close IMO. A keyword soup with do as prefix is a bit irregular, not similar to any other part of the language? Is while let a keyword soup as well? That one feels ok now, when you are used to it.
port
try!to use?
Can't ? be ported to use try! instead? This would allow for the use case where you want to get a Result return path, e.g. when debugging. With try! this is fairly easy, you just override the macro at the beginning of the file (or in lib/main.rs):
macro_rules! try {
($expr:expr) => (match $expr {
Result::Ok(val) => val,
Result::Err(err) => {
panic!("Error occured: {:?}", err)
}
})
}
You will get a panic stack trace starting from the first occurrence of try! in the Result return path. In fact, if you do try!(Err(sth)) if you discover an error instead of return Err(sth), you even get the full stack trace.
But when debugging foreign libraries written by people who haven't implemented that trick, one relies on try! usage somewhere higher in the chain. And now, if the library uses the ? operator with hardcoded behaviour, getting a stacktrace gets almost impossible.
It would be cool if overriding try! would affect the ? operator as well.
Later on when the macro system gets more features you can even panic! only for specific types.
If this proposal requires an RFC please let me know.
Ideally ? could just be extended to provide stack trace support directly, rather than relying on the ability to override try!. Then it would work everywhere.
Stack traces are just one example (though a very useful one, seems to me). If the Carrier trait is made to work, maybe that can cover such extensions?
On Sun, Feb 7, 2016 at 4:14 PM, Russell Johnston [email protected] wrote:
Ideally ? could just be extended to provide stack trace support directly, rather than relying on the ability to override try!. Then it would work everywhere.
— Reply to this email directly or view it on GitHub https://github.com/rust-lang/rust/issues/31436#issuecomment-181118499.
Without wanting to speculate, I think that it could work, albeit with some issues.
Consider the usual case where one has code returning some Result<V,E> value. Now we would need to allow for multiple implementations of the Carrier trait to coexist. In order to not run into E0119, one has to make all implementations out of scope (possibly through different traits which are per default not imported), and when using the ? operator, the user is required to import the wished implementation.
This would require everybody, even those who don't want to debug, to import their wished trait implementation when using ?, there would be no option for a predefined default.
Possibly E0117 can be an issue too if wanting to do custom Carrier implementations for Result<V,E>, where all types are outside bounds, so libstd should provide already provide a set of implementations of the Carrier trait with the most used use cases (trivial implementation, and panic! ing implementation, perhaps more).
Having the possibility to override via a macro would provide a greater flexibility without the additional burden on the original implementor (they don't have to import their wished implementation). But I also see that rust never had a macro based operator before, and that implementing ? via a macro isn't possible if catch { ... } is supposed to work, at least not without additional language items (return_to_catch, throw, labeled break with param as used in RFC 243).
I am okay with any setup which enables one to get Result stacktraces with an Err return path, while having only to modify a very small amount of code, prefferably at the top of the file. The solution should also work unrelated to how and where the Err type is implemented.
Just to chime in on bikeshedding: catch in { ... } flows pretty nicely.
catch! { ... } is another backcompat choice.
Also, not that I expect this to change anything, but a note that this is going to break multi-arm macros that were accepting $i:ident ?, in the same way that type ascription broke $i:ident : $t:ty.
Don't overdo the backwards compatibility, just treat catch as a keyword when followed by { (possibly only in expression position, but I'm not sure if that changes much compatibility-wise).
I can also imagine some possible problems that don't involve struct literals (e.g. let catch = true; if catch {}); but I prefer a minor breaking change over a more ugly syntax.
Didn't we have a for adding new keywords, anyways? We could offer some kind of from __future__ opt-in for new syntax; or specify a rust language version number on the command-line / in Cargo.toml.
I highly doubt that in the long term, we'll be able to work with only those keywords that are already reserved. We don't want our keywords to have three different meanings each, depending on context.
I agree. This isn't even the first RFC where this has come up (https://github.com/rust-lang/rfcs/pull/1444 is another example). I expect it won't be the last. (Also default from https://github.com/rust-lang/rfcs/pull/1210, although it's not an RFC I'm in favor of.) I think we need to find a way to add honest-to-god keywords instead of trying to figure out how to ad-hoc hack the grammar for every new case.
Wasn't the whole argument for not reserving several keywords prior to 1.0 that we'd definitely be introducing a way to add new keywords to the language backward compatibly (possibly by explicitly opting in), so there was no point? Seems like now would be a good time.
@japaric Are you interested in reviving your old PR and taking this on?
@aturon My implementation simply desugared foo? in the same way as try!(foo). It also only worked on method and function calls, i.e. foo.bar()? and baz()? work but quux? and (quux)? don't. Would that be okay for an initial implementation?
@japaric What was the reason for restricting it to methods and function calls? Wouldn't parsing it be easier as a general postfix operator?
What was the reason for restricting it to methods and function calls?
easiest way (for me) to test the ? expansion
Wouldn't parsing it be easier as a general postfix operator?
probably
@japaric It'd probably be good to generalize it to a full postfix operator (as @eddyb is suggesting), but it's fine to land ? with the simple desugaring and then add catch later.
@aturon Alright, I'll look into the postfix version by next week if no one beats me to it :-).
rebased/updated my PR in #31954 :-)
What about support for providing stack traces? Is that planned?