Join GitHub today
GitHub is home to over 31 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.
This comment has been minimized.
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.
This comment has been minimized.
|
@netvl That's covered by an earlier RFC for error interoperation. |
aturon
force-pushed the
rust-lang:master
branch
from
4c0bebf
to
b1d1bfd
Sep 16, 2014
This comment has been minimized.
This comment has been minimized.
|
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
|
|
||
| try { | ||
| foo()?.bar()? | ||
| } catch e { |
This comment has been minimized.
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.
This comment has been minimized.
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.
This comment has been minimized.
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.
This comment has been minimized.
This comment has been minimized.
glaebhoerl
Oct 3, 2014
Author
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.
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.
This comment has been minimized.
|
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.
This comment has been minimized.
|
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.
This comment has been minimized.
|
@aturon points out that for 1.0 staging we can add |
This comment has been minimized.
This comment has been minimized.
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.
This comment has been minimized.
|
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.
This comment has been minimized.
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.
This comment has been minimized.
|
@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
| 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.
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
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.
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
reviewed
Oct 7, 2014
|
|
||
| A `throws` clause on a function: | ||
|
|
||
| fn foo(arg; Foo) -> Bar throws Baz { ... } |
This comment has been minimized.
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.
This comment has been minimized.
This comment has been minimized.
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.
This comment has been minimized.
|
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.
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.
This comment has been minimized.
|
@glaebhoerl you're correct about @brson interesting point. I wonder what would be a compelling alternative set of terms. |
This comment has been minimized.
This comment has been minimized.
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.
This comment has been minimized.
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.
This comment has been minimized.
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.
This comment has been minimized.
|
@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.
This comment has been minimized.
|
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 |
nikomatsakis
referenced this pull request
Feb 5, 2016
Merged
Re-implement and test Manifestation::update #51
This comment has been minimized.
This comment has been minimized.
|
@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.
This comment has been minimized.
|
@glaebhoerl sorry, still catching up on the "paperwork" side here :) will open the tracking issue in a second. |
This comment has been minimized.
This comment has been minimized.
|
Regarding (I am presuming we are going to add |
nikomatsakis
referenced this pull request
Feb 5, 2016
Open
Tracking issue for `?` operator and `try` blocks (RFC 243, `question_mark` & `try_blocks` features) #31436
This comment has been minimized.
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.
This comment has been minimized.
|
OK, merged (with some edits). If anybody sees any place that I missed a reference to |
This comment has been minimized.
This comment has been minimized.
|
See in particular: 94390a2 |
aturon
changed the title
Trait-based exception handling
First-class error handling with `?` and `catch`
Feb 5, 2016
This comment has been minimized.
This comment has been minimized.
|
@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.
This comment has been minimized.
|
PR 33389 adds experimental support for the |
This comment has been minimized.
This comment has been minimized.
sciyoshi
commented
Sep 10, 2016
|
I didn't see any discussion in this thread about the possibility of reserving |
This comment has been minimized.
This comment has been minimized.
|
@sciyoshi Yes, types and values have separate syntax. |
withoutboats
pushed a commit
to withoutboats/rfcs
that referenced
this pull request
Jan 15, 2017
This comment has been minimized.
This comment has been minimized.
KalitaAlexey
commented
Feb 27, 2017
|
What is going to be implemented for the feature? |
glaebhoerl commentedSep 16, 2014
•
edited by mbrubeck
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