Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upFirst-class error handling with `?` and `catch` #243
Conversation
glaebhoerl
added some commits
Sep 16, 2014
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
netvl
Sep 16, 2014
This is really great, but I see a potential problem. The RFC does not say anything about how to translate different errors into each other, and I think this is very important. For example, your library may work with several other libraries, each providing its own kind of error, and sometimes you would want to pass these errors to the users of your library. The most natural way is to wrap them into your own error enum, with different variants for different kinds of original errors.
But under this proposal there is no support for such patterns at all. Frankly, I don't know even in the slightest how this can be done in syntactically light and convenient way and even if it is possible in principle. Exceptions in other language do not have this problem mainly due to subtyping and having special Exception supertype, and these features are not present in Rust.
I'm afraid that this can be a very common use-case, and, unfortunatley, ? operator won't help with it at all.
netvl
commented
Sep 16, 2014
|
This is really great, but I see a potential problem. The RFC does not say anything about how to translate different errors into each other, and I think this is very important. For example, your library may work with several other libraries, each providing its own kind of error, and sometimes you would want to pass these errors to the users of your library. The most natural way is to wrap them into your own error enum, with different variants for different kinds of original errors. But under this proposal there is no support for such patterns at all. Frankly, I don't know even in the slightest how this can be done in syntactically light and convenient way and even if it is possible in principle. Exceptions in other language do not have this problem mainly due to subtyping and having special I'm afraid that this can be a very common use-case, and, unfortunatley, |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
@netvl That's covered by an earlier RFC for error interoperation. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Ericson2314
Sep 17, 2014
Contributor
Ah, I was just thinking of making an RFC for "functional break" -- exactly your generalized return!
I am leery about most proposed syntactic sugars -- especially one as major as try..catch, and rather instead focus on using adding macros, or extending the macro system as necessary to give us what we want. (Hell, ideally I'd make bool an library-defined (enum) type, and even plain if..else a macro).
What I'd propose that people might actually agree with is simply adding the generalized break/return (Ideally one keyword could do everything, and the other would just be kept around for convenience), and making the try macro take an optional extra argument for a block lifetime:
match 'a: {
try!('a, foo());
try!('a, bar());
Ok(()) // edit: added this so it would type check
} {
None => ...,
_ => ()
}Not quite as pretty as try..catch, but on the other hand requires one only small addition to the language---and one that I'd argue more "rounds out" current features, since we already have loops as opposed to some system of mandatory tail calls, rather then delving it into new territory.
Besides my ascetic aversion to much syntactic sugar, I wonder whether the current demand for more control constructs will change with HKTs, and the design patterns they enable ;), and would vote for waiting until until we know the answer.
|
Ah, I was just thinking of making an RFC for "functional break" -- exactly your generalized return! I am leery about most proposed syntactic sugars -- especially one as major as try..catch, and rather instead focus on using adding macros, or extending the macro system as necessary to give us what we want. (Hell, ideally I'd make bool an library-defined (enum) type, and even plain if..else a macro). What I'd propose that people might actually agree with is simply adding the generalized break/return (Ideally one keyword could do everything, and the other would just be kept around for convenience), and making the match 'a: {
try!('a, foo());
try!('a, bar());
Ok(()) // edit: added this so it would type check
} {
None => ...,
_ => ()
}Not quite as pretty as try..catch, but on the other hand requires one only small addition to the language---and one that I'd argue more "rounds out" current features, since we already have loops as opposed to some system of mandatory tail calls, rather then delving it into new territory. Besides my ascetic aversion to much syntactic sugar, I wonder whether the current demand for more control constructs will change with HKTs, and the design patterns they enable ;), and would vote for waiting until until we know the answer. |
P1start
reviewed
Sep 17, 2014
active/0000-trait-based-exception-handling.md
| try { | ||
| foo()?.bar()? | ||
| } catch e { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
P1start
Sep 17, 2014
Contributor
Can’t e just be an arbitrary refutable pattern here, and allow multiple catch arms? So the example below becomes this:
try {
foo()?.bar()?
} catch Red(rex) {
baz(rex)
} catch Blue(bex) {
quux(bex)
}That way you only need one type of catch block and there’s less rightward drift.
P1start
Sep 17, 2014
Contributor
Can’t e just be an arbitrary refutable pattern here, and allow multiple catch arms? So the example below becomes this:
try {
foo()?.bar()?
} catch Red(rex) {
baz(rex)
} catch Blue(bex) {
quux(bex)
}That way you only need one type of catch block and there’s less rightward drift.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Ericson2314
Sep 17, 2014
Contributor
To me that syntax looks like if-let..else, and implies no guarantee of catching all cases. Catch should handle all variants---the alternative gives me bad memories of Java's RuntimeException.
Ericson2314
Sep 17, 2014
Contributor
To me that syntax looks like if-let..else, and implies no guarantee of catching all cases. Catch should handle all variants---the alternative gives me bad memories of Java's RuntimeException.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
P1start
Sep 17, 2014
Contributor
Just make it like match—all cases have to be covered. Just because it looks vaguely like ‘if…let’ doesn’t mean it has to behave like it. I’d immediately assume that all errors have to be handled anyway, regardless of syntax.
P1start
Sep 17, 2014
Contributor
Just make it like match—all cases have to be covered. Just because it looks vaguely like ‘if…let’ doesn’t mean it has to behave like it. I’d immediately assume that all errors have to be handled anyway, regardless of syntax.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
glaebhoerl
Oct 3, 2014
Contributor
I think this is also a reasonable choice. But I think I prefer the match-like syntax because it better matches the actual behavior and meaning, i.e. it makes the reader think of match, rather than of try-catch-catch from other languages, and this is in fact the correct intuition. The alternative would repurpose familiar syntax to mean something similar but significantly different, which I'm a little bit uneasy about.
(But again I think both are basically fine, I'm just explaining my preference.)
glaebhoerl
Oct 3, 2014
Contributor
I think this is also a reasonable choice. But I think I prefer the match-like syntax because it better matches the actual behavior and meaning, i.e. it makes the reader think of match, rather than of try-catch-catch from other languages, and this is in fact the correct intuition. The alternative would repurpose familiar syntax to mean something similar but significantly different, which I'm a little bit uneasy about.
(But again I think both are basically fine, I'm just explaining my preference.)
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
nrc
assigned
brson and
aturon
and unassigned
brson
Sep 18, 2014
glaebhoerl
referenced this pull request
Sep 27, 2014
Closed
Rename `Option`, add `Assert` trait #328
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
aturon
Oct 3, 2014
Member
First of all, thanks for writing another beautiful and thorough RFC. It's always a pleasure to read these.
The ideas you're proposing help overcome one of my worries with the initial ? proposal, namely that it was tied to exiting the function. While this is the common case in Rust code today (probably due, in part, to try!), and you can always factor your code into smaller functions to make it work, the extra flexibility in this RFC seems both appealing and not very complicated.
I also wholeheartedly agree that this design finds a middle ground between completely implicit propagation (traditional exceptions) and completely explicit propagation (Result without try!). It recovers much of the ergonomics of implicit propagation, while keeping control-flow jumps explicit.
I think that throw and throws are promising as well. My main worry there is that throws somewhat muddies the integration with return types, for better or for worse. I suspect it could and should be integrated with closure type syntax, if we decide to include it.
I'm undecided on the Carrier question, in part because we're (still!) trying to finalize conventions around the use of Result and Option.
Have you looked at the error interoperation RFC? Part of the goal there was to allow different error types to be automatically converted when using try!. The reason that works, however, is that the function's return type (and hence the target error type) is always explicitly written. This property would no longer hold with try-catch blocks, so I'm not sure how or whether automatic conversion would apply there. I'd be interested to get your thoughts.
So, on the whole I'm pretty enthusiastic about these ideas, and I think that if we add ?, we should do so in the form proposed here.
However, as you know, at the moment we're setting a pretty high standard for RFC acceptance: we're relentlessly focusing on what is needed for a solid 1.0 release (e.g., backcompat hazards or proposals that are needed for overall usability or coherence for 1.0). After the release, we will of course start considering more "nice-to-have" features.
Personally, I feel that having a solid error-handling story is an important aspect of 1.0, which is part of why I've been pushing on various related aspects (both conventions and sugar). It's not clear to me whether try! is enough to make a good first impression, but we also have our hands rather full implementing already-accepted features. It might be possible to accept this RFC but explicitly not as a 1.0 blocker; I'm not sure, but I'll discuss it with the team.
Two final questions:
-
If we have a
?operator as proposed here for error handling, does that change your opinion about!? What if, independently, macro syntax was changed to use@(which has been separately proposed; I know you're not fond of that, but hypothetically?) -
Do you have thoughts on the minimal steps we can take pre-1.0 to ensure that we can implement this feature later? The main issue seems to be the
trykeyword, which of course conflicts with thetry!macro. It's probably feasible (if confusing/ugly) to allow both, i.e. to treat!as part of the identifier. Alternatively, we could renametry!-- any suggestions?Actually, one possibility would be to implement
?as it was originally proposed (i.e., limited to returning from the current function) and then dump or renametry!. Rust code written in that style would continue to feel idiomatic if/when the rest of this RFC was implemented.
(As an aside, Standard ML at least has a form of try/catch that yields an expression.)
|
First of all, thanks for writing another beautiful and thorough RFC. It's always a pleasure to read these. The ideas you're proposing help overcome one of my worries with the initial I also wholeheartedly agree that this design finds a middle ground between completely implicit propagation (traditional exceptions) and completely explicit propagation ( I think that I'm undecided on the Have you looked at the error interoperation RFC? Part of the goal there was to allow different error types to be automatically converted when using So, on the whole I'm pretty enthusiastic about these ideas, and I think that if we add However, as you know, at the moment we're setting a pretty high standard for RFC acceptance: we're relentlessly focusing on what is needed for a solid 1.0 release (e.g., backcompat hazards or proposals that are needed for overall usability or coherence for 1.0). After the release, we will of course start considering more "nice-to-have" features. Personally, I feel that having a solid error-handling story is an important aspect of 1.0, which is part of why I've been pushing on various related aspects (both conventions and sugar). It's not clear to me whether Two final questions:
(As an aside, Standard ML at least has a form of try/catch that yields an expression.) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
nikomatsakis
Oct 3, 2014
Contributor
OK, so I read this over. This is pretty cool stuff. If I'm not mistaken, the throws syntax (and the Carrier trait) are backwards compatible extensions, right? If so, I'd probably prefer to move slowly and leave those out for now.
There are some things I really like about this proposal:
It means that the role of the try keyword is more analogous to try as traditionally used (it defines the scope of error-handling, which try! obviously doesn't do).
This also seems to give you roughly all the things you might want to do in a fairly compact way:
foo?-->try!(foo)try foo?.bar-->foo.map(bar)try foo?.bar?-->foo.and_then(bar)
|
OK, so I read this over. This is pretty cool stuff. If I'm not mistaken, the There are some things I really like about this proposal: It means that the role of the This also seems to give you roughly all the things you might want to do in a fairly compact way:
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
nikomatsakis
Oct 3, 2014
Contributor
@aturon points out that for 1.0 staging we can add ? as a synonym for try! for now, and add try-catch keywords in later. This is probably worth nothing in the RFC.
|
@aturon points out that for 1.0 staging we can add |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
aturon
Oct 3, 2014
Member
This also seems to give you roughly all the things you might want to do in a fairly compact way:
foo?-->try!(foo)try foo?.bar-->foo.map(bar)try foo?.bar?-->foo.and_then(bar)
Note that, in particular, this notation subsumes:
donotation when applied to theErrormonad,- Swift's
? try!that returns to the function boundary, which is not part of either of the two above.
I believe that even if we added monadic notation at some later time (which has many problems of its own), we would still profit from this specialized syntax for propagating and catching errors in a very lightweight way -- and a way that largely matches expectations when coming from a wide variety of other languages.
Note that, in particular, this notation subsumes:
I believe that even if we added monadic notation at some later time (which has many problems of its own), we would still profit from this specialized syntax for propagating and catching errors in a very lightweight way -- and a way that largely matches expectations when coming from a wide variety of other languages. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
nikomatsakis
Oct 3, 2014
Contributor
Also, I think I vaguely prefer the multiple catch arm syntax that @P1start suggested, since it resembles what other languages do, and because it unifies the two cases, though it obviously resembles match "less".
|
Also, I think I vaguely prefer the multiple catch arm syntax that @P1start suggested, since it resembles what other languages do, and because it unifies the two cases, though it obviously resembles |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
arcto
Oct 3, 2014
I really like the semantics and the ergonomics that this proposal would bring.
However, I can see this being used for a lot more than just exceptional failures. So I'm a bit unsure about the terminology and the naming of some of the constructs.
arcto
commented
Oct 3, 2014
|
I really like the semantics and the ergonomics that this proposal would bring. However, I can see this being used for a lot more than just exceptional failures. So I'm a bit unsure about the terminology and the naming of some of the constructs. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
glaebhoerl
Oct 4, 2014
Contributor
@Ericson2314 Feel free to submit a proposal for "functional break" if you like! I'm working on other things at the moment. (As discussed on discourse it seems like break would be the more appropriate choice, rather than return as I chose here.)
@aturon Thank you.
I think that
throwandthrowsare promising as well. My main worry there is thatthrowssomewhat muddies the integration with return types, for better or for worse. I suspect it could and should be integrated with closure type syntax, if we decide to include it.
Can you sketch how it might be implemented? I haven't thought about it deeply, but I wouldn't be surprised if it turned out to require higher-rank types for full generality. It's also not clear to me what the use case would be. (If you have a concrete fn that throws, it's polymorphic in the carrier, so it can be used at a closure type returning any concrete carrier. When or why would you want the closure itself to be polymorphic in the carrier?)
I'm undecided on the
Carrierquestion, in part because we're (still!) trying to finalize conventions around the use ofResultandOption.
Er, sorry: which Carrier question?
Have you looked at the error interoperation RFC? Part of the goal there was to allow different error types to be automatically converted when using
try!. The reason that works, however, is that the function's return type (and hence the target error type) is always explicitly written. This property would no longer hold withtry-catchblocks, so I'm not sure how or whether automatic conversion would apply there. I'd be interested to get your thoughts.
I have read it. With regards to the specific question as phrased, I suspect that the appropriate type for the try block can usually be inferred from the contents of the catch block. Do you have contrary examples? (But it's also not clear to me when you would want to do this -- wrapping in Box<Error> is something you would do to hide the specific error types used by upstream dependencies from downstream clients. But that's if you are propagating the errors. If you're handling them yourself with try..catch, why wouldn't you just inspect them directly? Why would you want to hide their types from yourself?)
Perhaps more importantly, the design as formulated in this RFC would preclude that kind of automatic conversion happening with the ? operator. Personally, I think that's a good thing. I recognize that the ergonomics of interfacing different errors types are important, but I would be deeply uncomfortable with baking this kind of ad-hoc special casing into the guts of the language. It's not even clear that this is the best way to do it, and having strong laws and ability to reason about code is much more important. ("Those who would give up essential Guarantees, to purchase a little temporary Convenience, deserve neither Guarantees nor Convenience." --Ben Franklin) I think a reasonable path forward would be to have a macro, separate from ?, which does do the automatic conversion (for instance rethrow!; I'm not sure if that's the best name). Then ? would have nice properties, the ergonomics of error-conversion would not be worse than proposed in the error interoperation RFC (which also assumed a macro), and it would be clear where automatic conversion may or may not happen.
However, as you know, at the moment we're setting a pretty high standard for RFC acceptance: we're relentlessly focusing on what is needed for a solid 1.0 release [...]
That's fine; this RFC was primarily intended to inform the ongoing debate about error handling. (But as far as I'm aware, an accepted RFC also does not imply that it has to, or will be, implemented before 1.0.)
Do you have thoughts on the minimal steps we can take pre-1.0 to ensure that we can implement this feature later?
I agree that the best approach would be to replace the try! macro with an ? operator restricted to the Result type and returning from the current function. This is a strict subset of the functionality described by the RFC, so I don't think it requires modifying the RFC in any way; it can just be considered "partially implemented" at that point.
If we have a
?operator as proposed here for error handling, does that change your opinion about!? What if, independently, macro syntax was changed to use@(which has been separately proposed; I know you're not fond of that, but hypothetically?)
It doesn't. My opinion about the ! operator is that it's "probably a bad idea". (It has a kind of nice symmetry with ?, but that doesn't make it wise.) More importantly however, I think that adding it would be premature and that doing so is not supported by the weight of the available evidence. The idea that convention-following APIs would be too cumbersome to use without it is highly speculative, especially given that other ergonomically significant features, such as in this RFC, are not yet available. There is also at least one indication that it is possible to avoid the need for it entirely. If, after half a year or so, experience shows that living without ! is still too painful, then a compelling case could possibly be made. But not now. (And I would be surprised.)
The fact that it also entails losing the ! syntax for macros is just anti-icing on the anti-cake.
(If we decide that we don't want an ! operator after all, can we then have it back for macros? My guess is no, because having two equivalent syntaxes is undesirable.)
try foo?.bar-->foo.map(bar)
try foo?.bar?-->foo.and_then(bar)
I can't help but notice that you left off the braces. It would be nice to allow this, but would it not run into the same ambiguities as if..else? (This might also be connected to the choice of catch syntax.)
Also, I think I vaguely prefer the multiple catch arm syntax that @P1start suggested, since it resembles what other languages do, and because it unifies the two cases, though it obviously resembles
match"less".
As in my comment to @P1start, I think the fact that it unifies the cases is nice, but having similar things look similar and different things look different feels more important.
However, I can see this being used for a lot more than just exceptional failures. So I'm a bit unsure about the terminology and the naming of some of the constructs.
I do think we can dispense with some of the stigmas and mythology surrounding exception handling in other languages, e.g. the hair-splitting about the meaning of "truly exceptional circumstances" and so on, which are due to the fact that they have to choose between error codes and exceptions, while here they are unified, and that their exceptions have various significant and undesirable aspects (e.g. not being tracked in the type system), while these don't. It can be used as just another control flow construct, and I think that's fine. Familiar syntax is still worthwhile. (See also e.g. enum for ADTs.)
|
@Ericson2314 Feel free to submit a proposal for "functional @aturon Thank you.
Can you sketch how it might be implemented? I haven't thought about it deeply, but I wouldn't be surprised if it turned out to require higher-rank types for full generality. It's also not clear to me what the use case would be. (If you have a concrete
Er, sorry: which
I have read it. With regards to the specific question as phrased, I suspect that the appropriate type for the Perhaps more importantly, the design as formulated in this RFC would preclude that kind of automatic conversion happening with the
That's fine; this RFC was primarily intended to inform the ongoing debate about error handling. (But as far as I'm aware, an accepted RFC also does not imply that it has to, or will be, implemented before 1.0.)
I agree that the best approach would be to replace the
It doesn't. My opinion about the The fact that it also entails losing the (If we decide that we don't want an
I can't help but notice that you left off the braces. It would be nice to allow this, but would it not run into the same ambiguities as
As in my comment to @P1start, I think the fact that it unifies the cases is nice, but having similar things look similar and different things look different feels more important.
I do think we can dispense with some of the stigmas and mythology surrounding exception handling in other languages, e.g. the hair-splitting about the meaning of "truly exceptional circumstances" and so on, which are due to the fact that they have to choose between error codes and exceptions, while here they are unified, and that their exceptions have various significant and undesirable aspects (e.g. not being tracked in the type system), while these don't. It can be used as just another control flow construct, and I think that's fine. Familiar syntax is still worthwhile. (See also e.g. |
reem
reviewed
Oct 7, 2014
active/0000-trait-based-exception-handling.md
| exceptions) matches what code might look like in a language with native | ||
| exceptions. | ||
| (This could potentially be extended to allow writing `throws` clauses on `fn` |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
reem
Oct 7, 2014
I actually don't think we can have one without the other - it would make using throws in a declaration a very leaky abstraction if I had to find out the expanded type if I wanted to store that function anywhere, which is especially true for closures.
reem
Oct 7, 2014
I actually don't think we can have one without the other - it would make using throws in a declaration a very leaky abstraction if I had to find out the expanded type if I wanted to store that function anywhere, which is especially true for closures.
reem
reviewed
Oct 7, 2014
| It is possible to carry the exception handling analogy further and also add | ||
| `throw` and `throws` constructs. | ||
| `throw` is very simple: `throw EXPR` is essentially the same thing as |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
reem
Oct 7, 2014
I want to like this a lot (it's much cleaner syntactically) but I fear the additional (apparent, if not real) complexity.
reem
Oct 7, 2014
I want to like this a lot (it's much cleaner syntactically) but I fear the additional (apparent, if not real) complexity.
reem
reviewed
Oct 7, 2014
active/0000-trait-based-exception-handling.md
| A `throws` clause on a function: | ||
| fn foo(arg; Foo) -> Bar throws Baz { ... } |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
reem
Oct 7, 2014
Looking at the expanded type below, I think this is a lot nicer and probably worth including if we go down this route.
reem
Oct 7, 2014
Looking at the expanded type below, I think this is a lot nicer and probably worth including if we go down this route.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
hatahet
Oct 7, 2014
I came across a couple of articles and thought they might be worth considering:
- http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx
- http://yosefk.com/blog/error-codes-vs-exceptions-critical-code-vs-typical-code.html
I realize though this is not 100% similar to C++'s (unchecked) or Java's (checked) exceptions.
hatahet
commented
Oct 7, 2014
|
I came across a couple of articles and thought they might be worth considering:
I realize though this is not 100% similar to C++'s (unchecked) or Java's (checked) exceptions. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
brson
Oct 8, 2014
Contributor
While I think this is an interesting and novel proposal, I am concerned about re-purposing the exception handling terminology ('try', 'catch', 'throw', 'exception').
- Exception handling has baggage, and people will draw conclusions based on the words alone.
- The mechanism is different from typical exceptions, has different performance characteristics and behavior.
- Rust already also includes much of the traditional exception handling mechanism, but in a non-traditional form, under a different name (panic), so calling something else 'exceptions' makes the issue rather muddy.
- Finally, this is such a cool idea that we might want to completely own it.
|
While I think this is an interesting and novel proposal, I am concerned about re-purposing the exception handling terminology ('try', 'catch', 'throw', 'exception').
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
suhr
commented
Oct 8, 2014
|
Will it make a mess when HKT is added to the language? |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
nikomatsakis
Oct 8, 2014
Contributor
@glaebhoerl you're correct about try {} vs try expr. Having to put braces is kind of a downer, but I agree that to do otherwise is inconsistent with our if/else story.
@brson interesting point. I wonder what would be a compelling alternative set of terms.
|
@glaebhoerl you're correct about @brson interesting point. I wonder what would be a compelling alternative set of terms. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
arthurprs
Oct 8, 2014
I second @brson thoughts. If this gets incorporated it'd be best to move away from "exception handling"-ish descriptions and stick with "error handling"
arthurprs
commented
Oct 8, 2014
|
I second @brson thoughts. If this gets incorporated it'd be best to move away from "exception handling"-ish descriptions and stick with "error handling" |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
huonw
Oct 8, 2014
Member
I can't help but notice that you left off the braces. It would be nice to allow this, but would it not run into the same ambiguities as if..else? (This might also be connected to the choice of catch syntax.)
@glaebhoerl you're correct about try {} vs try expr. Having to put braces is kind of a downer, but I agree that to do otherwise is inconsistent with our if/else story.
I'm missing something here: don't we require braces because it would be if cond expr else, that is, there's two adjacent expressions and that doesn't work. For try (AIUI) it is just try expr catch i.e. one expression and so perfectly OK from a grammar stand-point?
Also, it's not that inconsistent with if etc; we don't require delimiters around the condition of a if/while, or match head.
I'm missing something here: don't we require braces because it would be Also, it's not that inconsistent with |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
arcto
Oct 8, 2014
I'm not going to defend this position, but short-circuiting by using an early break/return or ?-operator can be seen as a more general feature than both error handling and exception handling. Suppose, for instance, that the "carrier" is an Option. A value of None is not necessarily an error.
arcto
commented
Oct 8, 2014
|
I'm not going to defend this position, but short-circuiting by using an early break/return or |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
glaebhoerl
Oct 8, 2014
Contributor
@huonw IIRC we require braces to avoid the common mistake from other C-like languages where an else clause is interpreted by the compiler as belonging to a different if than which the author intended.
- Exception handling has baggage, and people will draw conclusions based on the words alone.
This is a reasonable point. I was thinking of aiming for the title of "the language that finally got exceptions right".
The goal of this naming scheme is to provide a good intuition for the constructs. "It works like try-catch in other languages, except you need an explicit question mark to propagate". (Whereas otherwise it could end up being "that weird error handling construct that Rust has".) I think there's enough variety among exception handling implementations in existing languages that our deviations can fit under the same roof. (Haskell also uses exception handling terminology for their implementation, which has much more in common with this one than with others.)
But even that is probably overexplaining it. They have these names because the try-catch of existing languages is where the idea came from in the first place.
(Just as a thought experiment for anyone reading -- do you think it would have been easier or harder to grok the intended meaning and usage of these proposed constructs if they had been presented using different vocabulary, not connected to exception handling?)
- The mechanism is different from typical exceptions, has different performance characteristics and behavior.
- Rust already also includes much of the traditional exception handling mechanism, but in a non-traditional form, under a different name (panic), so calling something else 'exceptions' makes the issue rather muddy.
I think people are more attuned to meaning than to mechanism. If they're not meant to be caught then they're not really exceptions (accordingly, we call them panics), even if it involves unwinding.
All that said this is all very theoretical. My feeling is that trying to go with different names just for the sake of being different is likely to end up being more confusing, not less. But this could be assessed much more straightforwardly for a concrete set of alternative names.
|
@huonw IIRC we require braces to avoid the common mistake from other C-like languages where an
This is a reasonable point. I was thinking of aiming for the title of "the language that finally got exceptions right". The goal of this naming scheme is to provide a good intuition for the constructs. "It works like But even that is probably overexplaining it. They have these names because the (Just as a thought experiment for anyone reading -- do you think it would have been easier or harder to grok the intended meaning and usage of these proposed constructs if they had been presented using different vocabulary, not connected to exception handling?)
I think people are more attuned to meaning than to mechanism. If they're not meant to be caught then they're not really exceptions (accordingly, we call them panics), even if it involves unwinding. All that said this is all very theoretical. My feeling is that trying to go with different names just for the sake of being different is likely to end up being more confusing, not less. But this could be assessed much more straightforwardly for a concrete set of alternative names. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
nikomatsakis
Oct 8, 2014
Contributor
On Wed, Oct 08, 2014 at 06:04:41AM -0700, Huon Wilson wrote:
@glaebhoerl you're correct about try {} vs try expr. Having to put braces is kind of a downer, but I agree that to do otherwise is inconsistent with our if/else story.
I'm missing something here: don't we require braces because it would be
if cond expr else, that is, there's two adjacent expressions and that doesn't work. Fortry(AIUI) it is justtry expr catchi.e. one expression and so perfectly OK from a grammar stand-point?
Well, there are multiple reasons to require braces. One of them is that it lets you drop the parens, yes. The other is that it avoids ambiguity for cases like
if (cond1)
if (cond2)
something
else
something_else
in this case, the else is associated with the inner if, despite what the indentation suggests.
You can certainly construct analogous situations with the propose try/catch. One fix would be to permit dropping the {} if there is no catch.
|
On Wed, Oct 08, 2014 at 06:04:41AM -0700, Huon Wilson wrote:
Well, there are multiple reasons to require braces. One of them is that it lets you drop the parens, yes. The other is that it avoids ambiguity for cases like
in this case, the else is associated with the inner if, despite what the indentation suggests. You can certainly construct analogous situations with the propose try/catch. One fix would be to permit dropping the |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
brson
Oct 8, 2014
Contributor
(Just as a thought experiment for anyone reading -- do you think it would have been easier or harder to grok the intended meaning and usage of these proposed constructs if they had been presented using different vocabulary, not connected to exception handling?)
I do think try/catch provides the right intuition, and that's an argument that has won some (not all) naming debates in Rust in the past (and we even have several things called 'try' because it's such an intuitive concept). The word 'exception' is definitely the most worrisome here, though not having 'exceptions' but having try/catch requires some explanation.
We're probably going to end up with a long FAQ entry explaining the subtleties of exception and error handling as relates to Rust no matter what :)
I do think try/catch provides the right intuition, and that's an argument that has won some (not all) naming debates in Rust in the past (and we even have several things called 'try' because it's such an intuitive concept). The word 'exception' is definitely the most worrisome here, though not having 'exceptions' but having try/catch requires some explanation. We're probably going to end up with a long FAQ entry explaining the subtleties of exception and error handling as relates to Rust no matter what :) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
cc @wycats, this will interest you |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
wycats
Oct 8, 2014
Contributor
@nikomatsakis thanks for tagging me in.
I'm still digesting all of this. My initial knee-jerk reaction is about terminology: try may offer some of the right intuitions, but is also drags along the intuition of "anyone downstream from me can produce an exception, and I may not be able to tell". Very few people derive their intuitions from a language with checked exceptions only, and at least for me, "exception" and try {} have a very strong intuition of unpredictability, and throwing from an arbitrary downstream.
|
@nikomatsakis thanks for tagging me in. I'm still digesting all of this. My initial knee-jerk reaction is about terminology: |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
nikomatsakis
Oct 9, 2014
Contributor
I was thinking that, without the Carrier trait ideas, the role of the throw and catch keywords are unclear. That is, you can simplify the proposal to a ? operator and a try keyword that defines its scope, right? The other keywords are basically there to allow the code to be generic with respect to the "carrier" type.
|
I was thinking that, without the |
glaebhoerl
referenced this pull request
Oct 10, 2014
Closed
Allow loops to return values other than () #352
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
aturon
Oct 13, 2014
Member
Here are some more thoughts.
First, I think we should skip Carrier and bind directly to Result to start with. This will push people to use Result for error handling (and we also have conveniences to go from Option to Result), which is the desired convention in any case. It would keep the error handling story -- which is already novel -- as simple/concrete as possible. And we can always go more generic later, if desired.
Same with throw/throws.
Second, I agree with @brson's concerns about terminology and keyword choice -- especially given that we have unwinding with panic. Certainly, we should avoid calling this "exception handling". That said, I haven't been able to come up with a compelling alternative to try and catch, and it may be that they're the best choice despite these concerns.
Finally, I'd say that I don't particularly mind the braces for try (to me they help visually delimit the control-flow jump), and prefer having catch to trying to reuse match here (which is pretty ugly).
I'd like to move forward with this RFC soon. Does anyone have concrete proposals for alternative terminology? Does anyone think that Carrier should be committed to up front?
|
Here are some more thoughts. First, I think we should skip Same with Second, I agree with @brson's concerns about terminology and keyword choice -- especially given that we have unwinding with Finally, I'd say that I don't particularly mind the braces for I'd like to move forward with this RFC soon. Does anyone have concrete proposals for alternative terminology? Does anyone think that |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Ericson2314
Oct 14, 2014
Contributor
I forget what Rust's status is on empty enums, absurd patterns, and all that. But a way to make an uninhabited type (let's say Void) so that Result<A, Void> is isomorphic to A would be nice in order to make to make higher-order functions that are both maximally flexible, and don't make function arguments that will never error pay for the extra dispatching on Result.
Edit: I bring it up because I suspect the carrier trait could be used to achieve the same result. Conversely if empty types will suffice, it's one less reason to have a carrier trait.
|
I forget what Rust's status is on empty enums, absurd patterns, and all that. But a way to make an uninhabited type (let's say Edit: I bring it up because I suspect the carrier trait could be used to achieve the same result. Conversely if empty types will suffice, it's one less reason to have a carrier trait. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
nielsle
Oct 14, 2014
The ? operator looks useful, but I hope that the try! macro survives in one form or the other. The majority of my error handling follows one of the following two patterns, so I would like to avoid specifying catch blocks.
let y = try!(ctx.get_y());
try!(ctx.get_x()?.do_stuff());If we want the user to think in terms of error propagation then I believe that rust should encourage try!and or_else instead of try {} catch {}. That would be more consistent, and I think that it most use cases (albeit not all )
It might be nice to introduce ?= ... as sugar for = try!( ... ) (But that should probably be discussed elsewhere to avoid derailing this RFC)
nielsle
commented
Oct 14, 2014
|
The let y = try!(ctx.get_y());
try!(ctx.get_x()?.do_stuff());If we want the user to think in terms of error propagation then I believe that rust should encourage It might be nice to introduce |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
glaebhoerl
Oct 14, 2014
Contributor
@nikomatsakis I think that's two separate questions, "why is it this way" and "how could it be different". The keywords are there for intuition and convenience (the idea of try without catch actually came much later!); the Carrier trait is there because I think it's important to support Option. But the various features are nearly all separable (just take their "deeply expanded" definitions, without reference to the other features). So yes, just try and ? is also a thing you could do. In that case you could still define some sort of polymorphic unwrap_or_else in place of catch, if you wanted to, I think. (One strange thing here is that try { foo()?.bar() } doesn't entirely mean what it says -- it's always going to "succeed" and return to its caller, just collect any errors from the body. It would actually be better suggestive to write catch { foo()?.bar() }, where you're catching any exceptions that may be thrown. But then it's difficult to explain how that fits into the broader picture of try..catch. This kind of thing may also have been what @wycats was thinking of.)
@aturon I don't mind being incremental, at all, for the reasons you state. (Though I don't think we should be making any distinctions in meaning between Option and Result beyond what is implied by their structure.)
@nielsle Sorry, it's not quite clear to me: what's the difference between ? and try! in your examples? (? as proposed in the RFC is essentially a generalization of the current try!.)
Edit: @Ericson2314: The only reason for Carrier is to be able to support both Option and Result, and it is essentially an implementation detail of the ?, try..catch, etc. constructs. User code need never interact with it directly. (It might be useful for HOFs in some way, but that wasn't the goal.)
|
@nikomatsakis I think that's two separate questions, "why is it this way" and "how could it be different". The keywords are there for intuition and convenience (the idea of @aturon I don't mind being incremental, at all, for the reasons you state. (Though I don't think we should be making any distinctions in meaning between @nielsle Sorry, it's not quite clear to me: what's the difference between Edit: @Ericson2314: The only reason for |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mitsuhiko
Oct 14, 2014
Contributor
How did I miss this RFC? This is awesome. Much better than the comment I left in that other pull request :) I am strong +1 on the concepts in this RFC but I think that the terms try/catch should not be used because this really is not an exception system. Maybe just a variation of the words would indicate that it's something else (catch -> rescue maybe?).
I love that it supports both Option and Result but I wonder how well that works with the different rules about ignoring the return value.
I just want to point to this RFC for defaulted type parameters: #213. This is quite important if you end up in situations where you only care about the error part and the success part is generic. Without that RFC stuff like this would not work:
fn execute<T: FromSomething>(&self) -> Result<FromSomething, Error> {
FromSomething::value_from_something(...)
}
foo.execute()?With that RFC you could imply that T might just mean () for instance. I have this problem in my current library where people are forced to write stuff like this:
let _ : () = try!(foo.execute());|
How did I miss this RFC? This is awesome. Much better than the comment I left in that other pull request :) I am strong +1 on the concepts in this RFC but I think that the terms I love that it supports both I just want to point to this RFC for defaulted type parameters: #213. This is quite important if you end up in situations where you only care about the error part and the success part is generic. Without that RFC stuff like this would not work: fn execute<T: FromSomething>(&self) -> Result<FromSomething, Error> {
FromSomething::value_from_something(...)
}
foo.execute()?With that RFC you could imply that let _ : () = try!(foo.execute()); |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jaredr
Feb 2, 2016
If people don't mind a drive-by bikeshedding, let me suggest stay { }:
- You thought you were going to
return, but in fact you're going tostayright here - It can mean "to steady or support", which is a good match with error handling
- It can mean "to curb/check/postpone" as in to "stay your hand", which is a decent match with cancelling a hasty return.
- It verbs well: "the return was stayed by this block", or "the return stays in this block"
- It's concise
jaredr
commented
Feb 2, 2016
|
If people don't mind a drive-by bikeshedding, let me suggest
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
hauleth
Feb 2, 2016
@tikue it is exactly what and_then is for:
foo().and_then(Bar::bar).and_then(Baz::baz).map_err(MyErr::from)or
Ok(try!(foo().and_then(Bar::bar).and_then(Baz::baz)))But last one doesn't make much sense.
hauleth
commented
Feb 2, 2016
|
@tikue it is exactly what foo().and_then(Bar::bar).and_then(Baz::baz).map_err(MyErr::from)or Ok(try!(foo().and_then(Bar::bar).and_then(Baz::baz)))But last one doesn't make much sense. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
repax
Feb 2, 2016
@jaredr
You can still return from the function and break out of loops containing the proposed construct, so stay might be a little bit confusing as a keyword.
Incidentally, trap and catch might be misleading in the same respect. I.e. return Err(x) is not "caught".
repax
commented
Feb 2, 2016
|
@jaredr Incidentally, |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
tikue
commented
Feb 2, 2016
|
@hauleth it's not the same; |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
burdges
Feb 3, 2016
@hauleth We've a much more efficient implementation for Result though, or heck even for a state monad, so the situations must be distinguished somehow.
@rpjohnst Idris' effects types address similar issues, like the annoyance of monad transformers not being commutative, by being more restrictive than monads. I'd imagined it covered all the monads we're trying to avoid, but actually maybe it's close to the ones we want. It's another beast about which I know relatively little though.
I suppose a useful question is : Is there anything wrong with adding a state type to Carrier so that stored types become (State,Normal) and Exception, or maybe (State,Exception), and then ? helps the functions handle the state? I worry about this example because adding state seems like just sugar in Rust, but it's the example that comes to mind.
burdges
commented
Feb 3, 2016
|
@hauleth We've a much more efficient implementation for @rpjohnst Idris' effects types address similar issues, like the annoyance of monad transformers not being commutative, by being more restrictive than monads. I'd imagined it covered all the monads we're trying to avoid, but actually maybe it's close to the ones we want. It's another beast about which I know relatively little though. I suppose a useful question is : Is there anything wrong with adding a state type to |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
suhr
commented
Feb 3, 2016
|
Maybe @edwinb or @david-christiansen will tell more about Idris effect system. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
rpjohnst
Feb 3, 2016
@burdges Ah, so it's a way to make the desugaring work in more situations? Nifty, but I would think that as far as Rust goes we would want to keep control flow the same inside, outside, and across boundaries, rather than desugaring it in some cases.
rpjohnst
commented
Feb 3, 2016
|
@burdges Ah, so it's a way to make the desugaring work in more situations? Nifty, but I would think that as far as Rust goes we would want to keep control flow the same inside, outside, and across boundaries, rather than desugaring it in some cases. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
stevenblenkinsop
Feb 3, 2016
@rpjohnst - Ideally, you wouldn't be able to tell the difference, and the generated code would be the same either way. I'm not familiar enough with Idris to know whether this is possible in their model, though. But I agree, the behaviour of the construct shouldn't change depending on whether support for a given type is implemented in the compiler or in a library. That's why I'm skeptical of claims that the behaviour of this construct could be unified with a generalized monadic construct as long as they don't have a detailed design backing them up.
stevenblenkinsop
commented
Feb 3, 2016
|
@rpjohnst - Ideally, you wouldn't be able to tell the difference, and the generated code would be the same either way. I'm not familiar enough with Idris to know whether this is possible in their model, though. But I agree, the behaviour of the construct shouldn't change depending on whether support for a given type is implemented in the compiler or in a library. That's why I'm skeptical of claims that the behaviour of this construct could be unified with a generalized monadic construct as long as they don't have a detailed design backing them up. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
nikomatsakis
Feb 5, 2016
Contributor
Huzzah! The @rust-lang/lang subteam has decided to accept this RFC (with a few tweaks described below). Thanks everyone how participated in the rather, ahem, extended discussion (more than a year!). If you're interested in seeing a summary, we attempted to summarize the discussion in two previous comments that are still mostly complete.
Given the amount of discussion on this thread, I just want to reiterate that accepting the RFC is only the first step in the overall stability process. The next step is to open a tracking issue and begin work on implementation. Further discussion about this feature can be had on the tracking issue. Once we are satisfied with the state of the implementation -- and in particular we feel we have resolved the various unresolved questions -- we will start a second FCP period on the tracking issue itself. This lasts for one release cycle (6 weeks). We will then make a final decision about ungating. In the case of this RFC, there are two distinct feature-gates, one for the ? operator and one for the "try-catch" functionality. Most likely those will be stabilized at different times (and of course we can always refine further, creating new feature-gate for subsets of the functionality if necessary).
Some specific issues we plan to revisit prior to stabilizing:
- whether to extend to other types beyond
Result; - compatibility (or lack thereof) with a more general
donotation (and desirability thereof).
Now, on to the tweaks. We decided that for now we will simplify the RFC: rather than supporting the try/catch construct currently described, we'll just support a catch { ... } expression. catch will intercept any ? expressions within its body, just as try used to do. To get the equivalent of try { ... } catch { ... } functionality, then, one would do catch { ... }.unwrap_or(|v| match v { ... }).
Our reasoning was as follows:
- This variation has been proposed at various times on the RFC thread, most recently by the RFC author.
- Although
tryin many ways feels like the correct choice, the drawbacks are real:- opposite meaning of the
try!macro -- even if we were to deprecatetry!, it will be some time before we can do so (?must be stable first), and in that timetry!will remain the recommended pattern for stable crates; there is already a large body of code, blog posts, documentation, etc that refers totry!, and that will only get larger. So even once we deprecate it, it will be even longer until all of those references are updated (if theythey ever are). Moreover, in the interim, bothtry!andtrywill co-exist on nightly, which could be very confusing, given that they do very different things. - the lingering concerns that
try { } catch { }suggests automatic unwinding where none is happening
- opposite meaning of the
- The
catch(originally:try) keyword adds the real expressive "step up" here, thematch(originally:catch) was just sugar forunwrap_or. - It would be easy to add further sugar in the future, once we see how
catchis used (or not used) in practice. - There was some concern about potential user confusion about two aspects:
catch { }yields aResult<T,E>butcatch { } match { }yields justT;catch { } match { }handles all kinds of errors, unliketry/catchin other languages which let you pick and choose.
All right people, show's over, nothing to see here, move along (to the tracking issue). :)
|
Huzzah! The @rust-lang/lang subteam has decided to accept this RFC (with a few tweaks described below). Thanks everyone how participated in the rather, ahem, extended discussion (more than a year!). If you're interested in seeing a summary, we attempted to summarize the discussion in two previous comments that are still mostly complete. Given the amount of discussion on this thread, I just want to reiterate that accepting the RFC is only the first step in the overall stability process. The next step is to open a tracking issue and begin work on implementation. Further discussion about this feature can be had on the tracking issue. Once we are satisfied with the state of the implementation -- and in particular we feel we have resolved the various unresolved questions -- we will start a second FCP period on the tracking issue itself. This lasts for one release cycle (6 weeks). We will then make a final decision about ungating. In the case of this RFC, there are two distinct feature-gates, one for the Some specific issues we plan to revisit prior to stabilizing:
Now, on to the tweaks. We decided that for now we will simplify the RFC: rather than supporting the Our reasoning was as follows:
All right people, show's over, nothing to see here, move along (to the tracking issue). :) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
eddyb
Feb 5, 2016
Member
catch { ... }.unwrap_or(|v| match v { ... })
match catch { ... } { Ok(x) => x, Err(...) => ..., ... } might look better in some cases, fwiw.
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
repax
commented
Feb 5, 2016
|
Or like this: if let Err(e) = catch {
...
} {
handle(e);
} |
added a commit
to nikomatsakis/rfcs
that referenced
this pull request
Feb 5, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
logannc
Feb 5, 2016
Well, isn't that nifty. If the catch block is big that might look odd
having ... } { ... but its sort of nice that there is nothing else
required.
On Feb 5, 2016 1:43 PM, "Eduard-Mihai Burtescu" notifications@github.com
wrote:
catch { ... }.unwrap_or(|v| match v { ... })
match catch { ... } { Ok(x) => x, Err(...) => ..., ... } might look
better in some cases, fwiw.—
Reply to this email directly or view it on GitHub
#243 (comment).
logannc
commented
Feb 5, 2016
|
Well, isn't that nifty. If the catch block is big that might look odd
|
nikomatsakis
referenced this pull request
Feb 5, 2016
Merged
Re-implement and test Manifestation::update #51
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
glaebhoerl
Feb 5, 2016
Contributor
@nikomatsakis So where's the tracking issue? :)
@eddyb @logannc Wouldn't that run afoul of the same parser shenanigans which prevent using struct literals post-match? I recall some discussion upthread to that effect. I assume you could solve it by putting parentheses around the catch { }...
|
@nikomatsakis So where's the tracking issue? :) @eddyb @logannc Wouldn't that run afoul of the same parser shenanigans which prevent using struct literals post- |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
nikomatsakis
Feb 5, 2016
Contributor
@glaebhoerl sorry, still catching up on the "paperwork" side here :) will open the tracking issue in a second.
|
@glaebhoerl sorry, still catching up on the "paperwork" side here :) will open the tracking issue in a second. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
nikomatsakis
Feb 5, 2016
Contributor
Regarding catch as a match discriminant, I think it will run afoul of the rules regarding match expressions without parentheses, though the if let form would work fine (but of course is slightly different in its effect).
(I am presuming we are going to add catch as a contextual keyword; if it were a keyword from the start, we could potentially allow it as a match argument I guess.)
|
Regarding (I am presuming we are going to add |
nikomatsakis
referenced this pull request
Feb 5, 2016
Open
Tracking issue for `?` operator and `catch` expressions (RFC 243, `question_mark` feature) #31436
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
Tracking issue: rust-lang/rust#31436 |
nikomatsakis
merged commit 2daab80
into
rust-lang:master
Feb 5, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
nikomatsakis
Feb 5, 2016
Contributor
OK, merged (with some edits). If anybody sees any place that I missed a reference to try/catch or something like that, let me know.
|
OK, merged (with some edits). If anybody sees any place that I missed a reference to |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
See in particular: 94390a2 |
aturon
changed the title from
Trait-based exception handling
to
First-class error handling with `?` and `catch`
Feb 5, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
durka
Feb 5, 2016
Contributor
@nikomatsakis search for "try block" to find a bunch of missed replacements. And the "Laws" seem like they'll need to be rewritten.
|
@nikomatsakis search for " |
main--
referenced this pull request
Feb 14, 2016
Closed
clear_on_drop and clear_stack_on_return #1496
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
nrc
May 18, 2016
Member
PR 33389 adds experimental support for the Carrier trait. Since it wasn't part of the original RFC, it should get a particularly close period of examination and discussion before we move to FCP (which should probably be separate to the FCP for the rest of the ? operator). If the trait is still contentious after experimentation and discussion, then we can open an RFC (the language team felt this did not need to be the default path though). See this discuss thread for more details.
|
PR 33389 adds experimental support for the |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
sciyoshi
Sep 10, 2016
I didn't see any discussion in this thread about the possibility of reserving ? as syntax for nullable types, i.e. Option. I feel like Option (and Result) are common enough that they might eventually warrant shortened syntax, like u32? rather than Option<u32>. Would that still be possible with this RFC?
sciyoshi
commented
Sep 10, 2016
|
I didn't see any discussion in this thread about the possibility of reserving |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
@sciyoshi Yes, types and values have separate syntax. |
pushed a commit
to withoutboats/rfcs
that referenced
this pull request
Jan 15, 2017
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
KalitaAlexey
Feb 27, 2017
What is going to be implemented for the feature?
? is implemented. catch is being implemented. How about match?
KalitaAlexey
commented
Feb 27, 2017
|
What is going to be implemented for the feature? |
glaebhoerl commentedSep 16, 2014
•
edited by mbrubeck
Edited 1 time
-
mbrubeck
edited Apr 14, 2016 (most recent)
After a detour through thinking about first-class checked exceptions, I've now circled back around and convinced myself that @aturon's original idea of an
?operator for propagating exceptions is actually brilliant and the perfect middle path. But I also wanttry..catch.CLICKME