-
Notifications
You must be signed in to change notification settings - Fork 111
Multiple fixes to get rustup building #75
Conversation
This is an ergonomic concern. When matching on an error-chain error it is more convenient to write ``` match download_with_backend(backend, url, callback) { Err(Error(ErrorKind::BackendUnavailable(_), _)) => (), Err(e) => return Err(e), Ok(()) => return Ok(()), } ``` than ``` match download_with_backend(backend, url, callback) { Err(Error { kind: ErrorKind::BackendUnavailable(_), .. }) => (), Err(e) => return Err(e), Ok(()) => return Ok(()), } ```
Without this one cannot actually create links across crates.
Especially about pattern matching.
254dd1a
to
339c5ed
Compare
I want to comment on the tuple vs. named struct issue: It's probably a matter of taste, but personally I strongly prefer named fields on a struct where the fields have different types. I like tuple structs only in cases where all types are the same (like 3d coordinates). That was the one and only thing I didn't like about |
Ok for ResultExt, by why removing ChainedError and the struct? |
Thanks for the review @Yamakaky!
How does Error being defined as a struct impact your experience? Do you prefer matching on struct fields?
I don't understand the question. ChainedError still exists after this PR. What struct are you referring to?
What is it that #73 solves, and how? I feel strongly about everything in this patch and am going to merge it to get the fixes out. |
I'll publish a new build this afternoon. |
@@ -224,8 +224,8 @@ macro_rules! error_chain_processed { | |||
|
|||
$( | |||
$(#[$meta_links])* | |||
impl From<<$link_error_path as $crate::ChainedError>::ErrorKind> for $error_kind_name { | |||
fn from(e: <$link_error_path as $crate::ChainedError>::ErrorKind) -> Self { | |||
impl From<$link_kind_path> for $error_kind_name { |
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.
Well, you keep ChainedError, but you also remove it main advantage, so what the point? Now you have to specify ErrorKind
in links
.
What's the advantage of reverting to Error as a tuple? I only see the disadvantage that the macro code is less readable... Also, you talk about matching, but I can't see a use-case where you couldn't use the defined methods. |
@brson Yes indeed I prefer matching on named fields, because it is agnostic of field ordering. Of course I have to remember field names instead. But I rather remember something which has additional meaning instead of something arbitrary like randomly fixed ordering. And generally speaking, when I match pattern against named fields I feel more comfortable because I know it will break if the meaning of the fields changes, even if the type is still the same. Another use case is this: If I am writing a library and have to tell everyone "these are the errors you will get" I would like them to be in a nicely documented shape. And I also like explicit / self-documenting code. IDE-like tools like racer will be able to make meaningful auto-completions if someone puts a PS: I only make exceptions for tuple structs, if the struct has (a) one field or is (b) multi-dimensional over exactly the same type with the same meaning (like coordinates). |
PS: I also don't see the big disadvantage of matching on named fields. match foo {
Foo { ref name, ref age } => {
println!("age={}, name={}", age, name);
}
} https://play.rust-lang.org/?gist=91d74900f2e15304f5b754ad99a73609&version=stable&backtrace=0 |
OK for |
My example above was of course pretty silly. In case of only one matching branch it can be simplified to let or if let: let Foo { ref name, ref age } = foo;
println!("age={}, name={}", age, name); And this should work for errors from this macro crate accordingly: let MyError { ref kind, ref state } = my_error;
// ... |
I know how to do a match, I just want to know why you would do that. Aren't |
I added some docs on this subject, containing examples. Here's one:
This is a compact syntax. With fields it would look more like:
Which, while not significantly worse, is more characters and I find to be uglier. I admit that the tuple vs. struct change is one of personal preference, and not necessary for correctness. rustup does do matches like this. |
One other thing to consider with the structure layout is that the chaining protocol depends on the layout of the chained error structures - they pull chained error types apart during the linking. What this should mean is that, as long as the Error type layout doesn't chain, multiple revisions of error-chain should be compatible with each other. (hm, didn't explain this well. in a mtg, sorry). |
match Error::from("error!").kind() {
ErrorKind::InvalidToolchainName(_) => {}
} Even shorter. |
I was just about to post that, too. :-) Another argument would be that I've encountered error structs in the standard library which also have named fields, like here: https://doc.rust-lang.org/src/std/up/src/libstd/io/error.rs.html#69-72 And I always try to mimic the style I find there. |
Yeah, in this case it is. This only works when you know you have an error. If you have to match through the Result though then you have to match on the kind field. |
Yes, agree with @brson. Match on the error instead of the match some_result {
Ok(file) => file, // Found a matching file
Err(Error(ErrorKind::FileNotFound, _)) => continue, // Try next file
Err(err) => panic!(err), // Unexpected error
} That is, cases when you want to deal with some error kinds specially while still referencing the whole The errorkind is the first member of the tuple struct, so field ordering shouldn't be a problem. And we will soon get |
Anyway, I'm not closed to debate on tuples vs. structs here, but rustup relies on matching like this, as of now I still like the tuple matching better, and today I just wanted to get error-chain back in a state I'm happy with. I'm happy to revisit. Sorry for opening and pushing this through so quickly. |
And for the specification of |
In attempting to upgrade rustup to error-chain 0.6.2 I found multiple irreconcilable incompatibilities. A number of previous changes had unintended impacts. This restores error-chain to a state that rustup can build again.
The three changes this rolls back are:
chain_err
extension trait inside theerror_chain
crate. This extension must be defined on a per-crate basis for inference to work correctly.links { }
sections. This resulted in coherence errors in cross crate scenarios due to conflictingFrom<ErrorKind>
impls.Error
a struct. This type is a tuple so that pattern matching on it is nice.I've added test cases for these problems.
Fixes #68, probably others.
r? @Yamakaky
cc @alexcrichton @nikomatsakis