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

Add trait implementation guidance #312

Merged
merged 2 commits into from
Mar 20, 2018
Merged

Conversation

dhardy
Copy link
Member

@dhardy dhardy commented Mar 18, 2018

Close dhardy#13

Copy link
Contributor

@pitdicker pitdicker left a comment

Choose a reason for hiding this comment

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

I can't believe we never wrote this somewhere in the documentation since the discussion 😄.

Probably left more lines of comments than there is documentation...

@@ -81,6 +81,14 @@ pub mod le;
/// in this trait directly, then use the helper functions from the [`impls`]
/// module to implement the other methods.
///
/// It is recommended that implementations also implement:
///
/// - `Debug` but such that no internal details are output
Copy link
Contributor

Choose a reason for hiding this comment

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

For CSPRNGs this seems like something to recommend to me, but I am starting to feel like it matters less for small rngs. There it may even be desirable to print the state.

Copy link
Member Author

Choose a reason for hiding this comment

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

I doubt it matters much; the most that most people would want to do with the state is check whether it matches another state printed in the log, and it's not a very good way of checking states are equal in the first place (serialisation would be a better option).

/// It is recommended that implementations also implement:
///
/// - `Debug` but such that no internal details are output
/// - `Serialize` and `Deserialize` (from Serde), possibly behind a feature gate
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, something we talked a lot about 😄. Is behind a feature gate not mostly a practical matter, to keep the number of dependencies down?

Copy link
Member Author

Choose a reason for hiding this comment

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

It seems good practice for a library to keep dependencies optional where possible. Maybe I should expand the comment.

Copy link
Contributor

Choose a reason for hiding this comment

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

Or not mention it at all, seems like mixing concerns... Your choice.

///
/// - `Debug` but such that no internal details are output
/// - `Serialize` and `Deserialize` (from Serde), possibly behind a feature gate
/// - `Clone` if, and only if, the clone will have identical output to the original
Copy link
Contributor

Choose a reason for hiding this comment

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

We currently violate this with ThreadRng...

Do we want to guarantee the same output? Or do we want to guarantee the same generator?

I think we should just remove Clone from ThreadRng, but asking anyway. Would be another (small, I think) breaking change.

Copy link
Member Author

Choose a reason for hiding this comment

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

ThreadRng is Clone because it's a Rc<..>. So maybe we should expand the doc to something like:

  • if the clone would have identical output (i.e. be a true clone) or if the clone would be another handle to the same generator

Copy link
Contributor

Choose a reason for hiding this comment

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

With that definition OsRng could implement clone also. I prefer the definition you wrote of identical output.

Copy link
Collaborator

Choose a reason for hiding this comment

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

if the clone would have identical output (i.e. be a true clone) or if the clone would be another handle to the same generator

Does this imply every RNG should document what its clone does? Or should we hide the Rc and make ThreadRng clone the generator instead of the handle?

Copy link
Member Author

Choose a reason for hiding this comment

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

Technically ThreadRng meets the requirement: the clone has identical output to the original, except that the streams are not independent 😄

IMO ThreadRng supporting Clone causes no problems, and might be useful if someone wants to store it in a struct/tuple and then clone that.

Copy link
Member Author

Choose a reason for hiding this comment

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

@vks didn't see your comment until after posting. No, we definitely shouldn't allow cloning the internal ThreadRng generator, it's supposed to be a secure way to generate random data, not one which risks returning cloned streams. I don't see much need to document the cloning in general, though I will for ThreadRng because it is an exception.

@pitdicker
Copy link
Contributor

Could you add that RNGs should not implement Default, to guide towards proper seeding?

@dhardy dhardy added C-docs Documentation P-high Priority: high D-review Do: needs review labels Mar 19, 2018
/// - *never* implement `Copy` (accidental copies may cause repeated values)
/// - also *do not* implement `Default`, but instead implement `SeedableRng`
/// thus allowing use of `rand::NewRng` (which is automatically implemented)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not use NewRng for Default?

Copy link
Member Author

@dhardy dhardy Mar 19, 2018

Choose a reason for hiding this comment

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

PRNGs will be implemented in various crates outside of the rand crate, which provides NewRng. Default comes from the standard library. Therefore the locality of implementation rules make this impossible. PRNGs could implement Default themselves, but they'd have to depend on rand to do so, which I don't think they should. Other than that I guess it's a good idea, though possibly a little confusing.

@pitdicker
Copy link
Contributor

Looks good to me! Ready to merge?

(The CI has some trouble with installing cargo-update, but is otherwise green.)

@dhardy
Copy link
Member Author

dhardy commented Mar 20, 2018

Failed on retry too. Never mind, I'll just merge.

@dhardy dhardy merged commit e10458b into rust-random:master Mar 20, 2018
@dhardy dhardy deleted the trait-guide branch March 23, 2018 18:01
pitdicker pushed a commit that referenced this pull request Apr 4, 2018
Add trait implementation guidance
@pitdicker pitdicker mentioned this pull request Apr 10, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-docs Documentation D-review Do: needs review P-high Priority: high
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants