-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
First-class error handling with ?
and catch
#243
First-class error handling with ?
and catch
#243
Conversation
… but it somehow got lost in the shuffle
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, |
@netvl That's covered by an earlier RFC for error interoperation. |
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. |
|
||
try { | ||
foo()?.bar()? | ||
} catch e { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO, if something should behave like match
, it should look like match
.
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.) |
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:
|
@aturon points out that for 1.0 staging we can add |
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. |
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 |
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. |
@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. |
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` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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. |
While I think this is an interesting and novel proposal, I am concerned about re-purposing the exception handling terminology ('try', 'catch', 'throw', 'exception').
|
Will it make a mess when HKT is added to the language? |
@glaebhoerl you're correct about @brson interesting point. I wonder what would be a compelling alternative set of terms. |
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" |
I'm missing something here: don't we require braces because it would be Also, it's not that inconsistent with |
I'm not going to defend this position, but short-circuiting by using an early break/return or |
@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. |
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 |
Regarding (I am presuming we are going to add |
Tracking issue: rust-lang/rust#31436 |
OK, merged (with some edits). If anybody sees any place that I missed a reference to |
See in particular: 94390a2 |
?
and catch
@nikomatsakis search for " |
PR 33389 adds experimental support for the |
I didn't see any discussion in this thread about the possibility of reserving |
@sciyoshi Yes, types and values have separate syntax. |
futures-cpupool: enrich `Builder` with thread name prefix
What is going to be implemented for the feature? |
Why does the try block wrap the return value in whatever the successful wrapper value is, for example, Ok for Result or Some for Option? It's very confusing because functions returning those types don't do it. It's very confusing, especially with wrapped types or if you just want to return the value the normal way. In a situation where you could just return a Result from a function, for a try block, you have to add a "?" to the end for no reason. |
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