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

sync: improve docs for watch channels #5954

Merged
merged 6 commits into from
Aug 28, 2023
Merged

Conversation

sunshowers
Copy link
Contributor

Motivation

I found the watch docs as written to be somewhat confusing.

  • It wasn't clear to me whether values are marked seen or not at creation/subscribe time.
  • The example also confused me a bit, suggesting a while loop when a do-while loop is generally more correct.
  • I noticed a potential race with borrow that is no longer an issue with borrow_and_update.

Solution

Update the documentation for the watch module to try and make all this clearer.

I found the watch docs as written to be somewhat confusing.

* It wasn't clear to me whether values are marked seen or not at
  creation/subscribe time.
* The example also confused me a bit, suggesting a while loop when a
  do-while loop is generally more correct.
* I noticed a potential race with `borrow` that is no longer an issue
  with `borrow_and_update`.

Update the documentation to try and make it clearer.
@github-actions github-actions bot added the R-loom-sync Run loom sync tests on this PR label Aug 27, 2023
@hawkw hawkw self-requested a review August 27, 2023 00:37
//! use [`Receiver::borrow_and_update()`].
//!
//! To access the latest value but **not** mark it as seen, use
//! [`Receiver::borrow()`].
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Might want to mention here that if the value has already been seen its state doesn't change.

Copy link
Contributor

@Darksonn Darksonn left a comment

Choose a reason for hiding this comment

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

This looks reasonable to me.

Comment on lines 30 to 32
//! * On completion, the [`changed`] method marks the new value as *seen*. If
//! [`Receiver::changed()`] is called again, it will not be ready unless a
//! subsequent value is sent.
Copy link
Contributor

Choose a reason for hiding this comment

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

This sentence is a bit confusing. Can we rephrase "not be ready" to "not return immediately" or similar?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, thanks!

@Darksonn Darksonn added T-docs Topic: documentation A-tokio Area: The main tokio crate M-sync Module: tokio/sync labels Aug 27, 2023
Copy link
Contributor

@Darksonn Darksonn left a comment

Choose a reason for hiding this comment

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

Only minor nits. Overall looks good!

Comment on lines 29 to 33
//! * The [`changed`] method returns `Ok(())` on receiving a new value, or
//! `Err(_)` if the [`Sender`] has been closed.
//! * On completion, the [`changed`] method marks the new value as *seen*. If
//! [`Receiver::changed()`] is called again, it will not return immediately
//! unless a subsequent value is sent.
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps it would make sense to add this point somewhere here?

  • If the latest value is unseen when calling changed, then changed will return immediately. If the latest message is seen, then it will sleep until a new message is sent.

I don't think the current way its written make this sufficiently clear.

Then the second point can also be simplified to this:

  • On completion, the changed method marks the new value as seen.

Copy link
Member

Choose a reason for hiding this comment

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

+1 to @Darksonn's comment. Also, perhaps some of this documentation should also be copied into the Receiver::changed() docs?

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 like this a lot. Updated with this + also a mention that the sender can be dropped.

Copy link
Member

@hawkw hawkw left a comment

Choose a reason for hiding this comment

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

Overall, this looks great, thanks for working on it! I commented on some very minor nitpicks and edits, let me know what you think!

tokio/src/sync/watch.rs Show resolved Hide resolved
tokio/src/sync/watch.rs Outdated Show resolved Hide resolved
Comment on lines 29 to 33
//! * The [`changed`] method returns `Ok(())` on receiving a new value, or
//! `Err(_)` if the [`Sender`] has been closed.
//! * On completion, the [`changed`] method marks the new value as *seen*. If
//! [`Receiver::changed()`] is called again, it will not return immediately
//! unless a subsequent value is sent.
Copy link
Member

Choose a reason for hiding this comment

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

+1 to @Darksonn's comment. Also, perhaps some of this documentation should also be copied into the Receiver::changed() docs?

tokio/src/sync/watch.rs Outdated Show resolved Hide resolved
Comment on lines 17 to 18
//! To access the **latest** value stored in the channel and mark it as *seen*,
//! use [`Receiver::borrow_and_update()`].
Copy link
Member

Choose a reason for hiding this comment

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

do you think it's worth explicitly stating something like "borrow_and_update() should be preferred if the receiver intends to await notifications from changed()"?

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 kinda added that to the examples section but maybe I should move it up to this section.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved it into a new section titled "borrow_and_update versus borrow". Hopefully that works.

Comment on lines +21 to +22
//! [`Receiver::borrow()`]. (If the value has already been marked *seen*,
//! [`Receiver::borrow()`] is equivalent to [`Receiver::borrow_and_update()`].)
Copy link
Member

Choose a reason for hiding this comment

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

do you think it's worth explicitly stating something like "borrow_and_update() should be preferred if the receiver intends to await notifications from changed(), but it is not required if the receiver is just looking at the current value of the shared state without waiting for changes"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added this to the new section, and also mentioned why borrow can be more convenient (it's &self).

Copy link
Member

Choose a reason for hiding this comment

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

do you think we should maybe add a

Suggested change
//! [`Receiver::borrow()`]. (If the value has already been marked *seen*,
//! [`Receiver::borrow()`] is equivalent to [`Receiver::borrow_and_update()`].)
//! [`Receiver::borrow()`]. (If the value has already been marked *seen*,
//! [`Receiver::borrow()`] is equivalent to [`Receiver::borrow_and_update()`].)
//!
//! See [here](#borrow-and-update-versus-borrow) for more information on when
//! to use these methods.

or something?

//! method is ready when a new, *unseen* value is sent via the [`Sender`] half.
//!
//! * The [`changed`] method returns `Ok(())` on receiving a new value, or
//! `Err(_)` if the [`Sender`] has been closed.
Copy link
Member

Choose a reason for hiding this comment

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

very tiny nit, not actually important: this returns a public named error type, so we could actually reference it:

Suggested change
//! `Err(_)` if the [`Sender`] has been closed.
//! `Err(`[`errors::RecvError`]`)` if the [`Sender`] has been closed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@sunshowers
Copy link
Contributor Author

Done, thanks for the comments.

Copy link
Member

@hawkw hawkw left a comment

Choose a reason for hiding this comment

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

looks great to me overall! i'd like to see links back to the section on "borrow_and_update versus borrow" in the method docs for those methods --- mind adding that?

Comment on lines +42 to +54
//! ## `borrow_and_update` versus `borrow`
//!
//! If the receiver intends to await notifications from [`changed`] in a loop,
//! [`Receiver::borrow_and_update()`] should be preferred over
//! [`Receiver::borrow()`]. This avoids a potential race where a new value is
//! sent between [`changed`] being ready and the value being read. (If
//! [`Receiver::borrow()`] is used, the loop may run twice with the same value.)
//!
//! If the receiver is only interested in the current value, and does not intend
//! to wait for changes, then [`Receiver::borrow()`] can be used. It may be more
//! convenient to use [`borrow`](Receiver::borrow) since it's an `&self`
//! method---[`borrow_and_update`](Receiver::borrow_and_update) requires `&mut
//! self`.
Copy link
Member

Choose a reason for hiding this comment

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

this is fantastic --- but i think the doc comments for borrow and borrow_and_update probably ought to link back to this section. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

tokio/src/sync/watch.rs Show resolved Hide resolved
Comment on lines +21 to +22
//! [`Receiver::borrow()`]. (If the value has already been marked *seen*,
//! [`Receiver::borrow()`] is equivalent to [`Receiver::borrow_and_update()`].)
Copy link
Member

Choose a reason for hiding this comment

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

do you think we should maybe add a

Suggested change
//! [`Receiver::borrow()`]. (If the value has already been marked *seen*,
//! [`Receiver::borrow()`] is equivalent to [`Receiver::borrow_and_update()`].)
//! [`Receiver::borrow()`]. (If the value has already been marked *seen*,
//! [`Receiver::borrow()`] is equivalent to [`Receiver::borrow_and_update()`].)
//!
//! See [here](#borrow-and-update-versus-borrow) for more information on when
//! to use these methods.

or something?

@sunshowers
Copy link
Contributor Author

Added links. I think this is ready to go now. Thanks!

Copy link
Member

@hawkw hawkw left a comment

Choose a reason for hiding this comment

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

looks great to me!

@hawkw hawkw merged commit cb1e10b into tokio-rs:master Aug 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio Area: The main tokio crate M-sync Module: tokio/sync R-loom-sync Run loom sync tests on this PR T-docs Topic: documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants