-
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
RFC: Error conventions, take 3 #236
Conversation
I am generally in favor of this. I am a little concerned about the naming, though. A I am more fond of the Assuming a better naming convention can be found for "don't block" APIs ( |
It seems to me that it's reasonable to expect that, due to its dynamic nature, a I would like the convention to take this point of view. Am I wrong? Concretely, I'd like to reverse the recommendation of Why? Because the type system is not able to guarantee that the operation will succeed the users of the API should be nudged/encouraged to use the safe variant that returns a |
It's not my intention to nitpick. But would it be useful to elaborate on "coherent state"? I suppose that it means that invariants are preserved, but not requiring a complete roll-back. Thus, Obstructed operations may have side effects. To be on the safe side these invariants should be documented in the API. |
I like this very much! It should be encouraged to design APIs that minimise the contract as much as possible by using specific types for input and output. In my opinion one can often do more. That is, extend this principle to dynamic aspects. Some examples: |
@arcto In what context would you be able to do anything useful with an |
@sfackler I've been in the situation where a RefCell violation would indicate a cyclic in a data structure that was supposed to be a DAG. But the data structure came from user input and hence was out of my control. So you could leverage RefCell to do the checking for you, if you wanted. |
such, calling `recv()` is an _assertion_ that the other end of the channel is | ||
still alive, which will propagate failures from the other end of the | ||
channel. On the other hand, since there is no separate way to atomically test | ||
whether the other end has hung up, channels provide a `recv_opt` variant that |
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.
Wouldn't it be more convenient to name function recv_result
instead of recv_opt
if it's returning Result and not Option.
@kballard Thanks for the feedback. I've added some brief text on a few alternative names for the @pkondzior I added your |
If the API designer is willing to do that, they should just leave off the failing variant and let the client use Admittedly, I'd prefer not to have this exception at all, and simply to say that if you provide a I am definitely curious to hear the community's feedback on this point, in particular: do people agree that it's very occasionally justified to have both variants? |
I feel like concurrency primitives like channels are really the only places where you'd want failing and non-failing variants. In the case of something like enum BorrowState {
Unborrowed,
ImmutablyBorrowed(uint),
MutablyBorrowed,
}
impl<T> RefCell<T> {
fn state(&self) -> BorrowState { ... }
} This avoids requiring tons of If we had unwrap sugar, then I'd be fine with |
@sfackler Yes! I actually like that perspective quite a bit. Concurrency primitives are special, since they are the sole way of communication between tasks and therefore the source of failure propagation. So we can give a clear guideline/justification for the variants in that case. Unless @nikomatsakis objects, I think I will rewrite the RFC to argue for such a guideline. |
They're also special in that it isn't possible to make a |
Yes; this argues for having a |
@nikomatsakis raised an interesting question on IRC today: is the material about allowing both failing and Another way of putting this: if we had something like the Or do we believe the argument that e.g. channels should "fail by default" as part of the propagation model? |
If we had |
I agree. The |
However, having |
On Sun, Sep 14, 2014 at 09:22:34PM -0700, Aaron Turon wrote:
So I went around and around on this question. I had a super long All other things being equal, using
However, usability intrudes, and in reality sometimes it is better to
Now, Lastly, @sfackler proposed removing the "try" variants on
|
On Tue, Sep 16, 2014 at 01:34:26AM -0700, Jonathan Reem wrote:
I am not sure I understand. It seems to be the opposite: having |
I think that On Tuesday, September 16, 2014, Niko Matsakis notifications@github.com
Thanks, |
I'd be very careful when placing a |
You and I would be, my concern is would newbies and those coming from other On Tuesday, September 16, 2014, arcto notifications@github.com wrote:
Thanks, |
|
||
* `try_` prefix. Also connotes exception handling, but has an unfortunately | ||
overlap with the common use of `try_` for nonblocking variants (which is in | ||
play for `recv` in particular). |
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.
The use of try_
in try_recv
actually fits the pattern quite well: it signals a failure to receive any data. It even returns a Result.
IMHO, try_<something>
makes much more sense in English that the other two forms. Also, there's the precedent of Try
in C# being used for exactly the same purpose.
I must admit I have a problem with "For contract violations fail the task". The erlang philosophy matches the language's target function to "support distributed, fault-tolerant, soft-real-time, non-stop applications." I understood rust's target audience to be larger than this. My experience is that the majority of unexpected errors of a large/complex GUI application tend to be contract errors, discovered in the field simply because the complexity of the application architecture lead to dynamics that were not anticipated. Index out of bounds is not an untypical experience. To provide no other failure mechanism for Index out of bounds errors will lead to either, a) mandatory use of wrapper classes around slice, or b) making tasks very fine grained, and "catching" contract failure errors at the boundary. Both of which are doable - but fall into the category of "working around the deficiencies of the language". Moreover; many contract errors occur in third party code for which I have no visibility, and over which I have no control. This removes (a) above as an option - leaving me only with (b). I worry about the additional cost that maintaining this fine grained task structure will impose. |
* Ember.String deprecation RFC * Update on RFC Update on RFC based on feedback * Fix addon name * Update 0000-deprecation-ember-string.md * Update 0000-deprecation-ember-string.md * Update 0000-deprecation-ember-string.md * Update 0000-deprecation-ember-string.md * Minor fixes * Update 0000-deprecation-ember-string.md * Update 0000-deprecation-ember-string.md * Update 0000-deprecation-ember-string.md typo * Update 0000-deprecation-ember-string.md (#2) * Update 0000-deprecation-ember-string.md * Update 0000-deprecation-ember-string.md * Update 0000-deprecation-ember-string.md * Update 0000-deprecation-ember-string.md * Update 0000-deprecation-ember-string.md * Fix minor wording * Update 0000-deprecation-ember-string.md * Remove last appearance of @ember/component * rename RFC file
This is a conventions RFC for formalizing the basic conventions around error handling in Rust libraries.
The high-level overview is:
Result
(or, less often,Option
). (Recover from obstructions at a fine grain.)This RFC follows up on two earlier attempts by giving more leeway in when to fail the task.
Rendered