Skip to content
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

rust: use thiserror for error types #4341

Merged
merged 1 commit into from
Nov 18, 2020
Merged

Conversation

wchargin
Copy link
Contributor

Summary:
Our errors now have nice string formatting, easier From conversions,
and std::error::Error implementations.

Test Plan:
Included some tests for the Display implementations. They’re often not
necessary—one benefit of deriving traits is that you can be confident in
the implementation without manually testing it. But sometimes, if the
format string is non-trivial, it can be nice to actually see the full
text written out.

wchargin-branch: rust-use-thiserror

Summary:
Our errors now have nice string formatting, easier `From` conversions,
and `std::error::Error` implementations.

Test Plan:
Included some tests for the `Display` implementations. They’re often not
necessary—one benefit of deriving traits is that you can be confident in
the implementation without manually testing it. But sometimes, if the
format string is non-trivial, it can be nice to actually see the full
text written out.

wchargin-branch: rust-use-thiserror
wchargin-source: 0f8009c3b96619f2eb4649353487dc996b45a712
@wchargin wchargin added the core:rustboard //tensorboard/data/server/... label Nov 17, 2020
@google-cla google-cla bot added the cla: yes label Nov 17, 2020
@@ -30,7 +30,13 @@ pub struct MaskedCrc(pub u32);
// Implement `Debug` manually to use zero-padded hex output.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment still relevant for Debug, now that it writes Masked({}) without using the :#010x padding option?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think so. The point of the comment is to explain why we don’t
just write #[derive(Debug)]. This patch changes the implementation,
but not the behavior. If we derived Debug, the output would still be
MaskedCrc(4660) rather than MaskedCrc(0x1234), so the comment is
still as helpful as it was before.

In fact, I think it’s a bit more helpful than before, since before the
:#010x? was at least immediately following in the code. Now, if you
don’t look at the Display implementation, it’d be reasonable to ask,
“this just wraps the Display in the struct name; at that point, why
not just derive Debug?”—which the comment answers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the tests answer it, too. :-)

}

impl Display for MaskedCrc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand why the '_ is needed in fmt::Formatter<'_>.

In Rust docs, some examples don't include it [1], while others do [2]. From what I gather, '_ is declaring a lifetime annotation for the Formatter, but we aren't using '_ anywhere else. Could you help me understand why it is needed?

[1] https://doc.rust-lang.org/std/fmt/struct.Formatter.html#examples
[2] https://doc.rust-lang.org/std/fmt/trait.UpperHex.html#examples

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You’re right—it isn’t needed here. You can read '_ as “infer the
correct lifetime”. The general feature is called lifetime elision, and
the '_ syntax was introduced in rust-lang/rfcs#2115; see conversation
for discussion, or the diff for the final text:

  • You can write '_ to explicitly elide a lifetime, and it is deprecated to
    entirely leave off lifetime arguments for non-& types

The reason that it’s here is that I write trait implementations by
typing impl Display for MaskedCrc {} and then asking rust-analyzer to
fill out method stubs for all required methods (<Space>j1 in my
editor), which generates:

impl Display for Foo {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        todo!()
    }
}

Given that it’s optional, I don’t have a strong preference. In the
particular case of fmt::Formatter, I do actually find it helpful to
recall that Formatter is parameterized by a lifetime, since this
affects how you can use it and isn’t entirely obvious. As the RFC says:
“The '_ marker makes clear to the reader that borrowing is
happening
, which might not otherwise be clear.”

I’m also weakly inclined to deem it acceptable to write the code that
rust-analyzer generates, so that I don’t have to always correct it. But
if we want to have a policy of eliding lifetimes implicitly rather than
implicitly absent a strong reason, I would be open to considering that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the links and explanation!

The RFC sheds a lot of light for me on why they decided it was good to explicitly use the '_ placeholder. I don't yet have an opinion on when we should do it, but Rust reference also says "For lifetimes in paths, using '_ is preferred", so in this case it's seems idiomatic.

@wchargin wchargin merged commit a9e1bba into master Nov 18, 2020
@wchargin wchargin deleted the wchargin-rust-use-thiserror branch November 18, 2020 21:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes core:rustboard //tensorboard/data/server/...
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants