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 rand::range and rand::shuffle as top-level helper functions #1488

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

oconnor663
Copy link

@oconnor663 oconnor663 commented Aug 14, 2024

Original issue: #989

In that issue, @newpavlov originally proposed several new helpers:

  • gen_range
  • fill
  • gen_bool/gen_ratio
  • choose/choose_mut
  • shuffle

As I started playing with implementing these, I narrowed it down to two functions that seemed the most useful/obvious to me:

  • range: The helper I most frequently wish I had. A flexible way to get a random float or an index into a slice. A "pit of success" around the random::<usize>() % len mistake. Good integration with Rust's native range syntax. Renamed from gen_range, mainly because it's more convenient to type/read, and also to give more space to the upcoming gen keyword.
  • shuffle: An obvious/straightforward API. Useful in small examples, tests, etc.

In my mind, the case for these others is less compelling:

  • fill: The most common use case might be generating 128-bit or 256-bit seeds/keys, but random() already works for arrays up to size 32.
  • gen_bool: Also doable by comparing a float to random(), and that alternative might be easier to read.
  • choose: Useful, but you want two or three different variants (&T, and &mut T, and maybe T: Copy). Easier to get an index from range() and let the caller decide what to do with it.

So in this PR I've implemented rand::range and rand::shuffle. Very interested to get other folks' thoughts.

/// println!("{}", y);
/// ```
///
/// If you're calling `range()` in a loop, caching the generator as in the
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you mean caching the distribution?

Copy link
Author

Choose a reason for hiding this comment

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

This wording is copied from lines 135-136 above.

Copy link
Member

Choose a reason for hiding this comment

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

If the range is non-constant, caching the distribution helps. Either way, caching the result of rand::thread_rng also helps (slightly).

@dhardy
Copy link
Member

dhardy commented Aug 21, 2024

Some thoughts on this:

  • These functions make rand easier/quicker to use in some very specific cases
  • These functions hide the source of the randomness; this is okay though not exactly ideal
  • The real reason this is more convenient than rand::thread_rng().gen_range(0..len) or rand::thread_rng.shuffle(array) is that the latter require trait imports. Custom preludes might help, but we can't bet on that ever happening.
  • We could re-implement the Rng methods under ThreadRng using inherent methods which forward to the trait methods. This avoids the need to import Rng (for ThreadRng only, though there's no reason other RNGs couldn't do the same thing) and shouldn't cause issues (inherent methods are always resolved over trait methods).
  • Inherent traits provides much the same capability as above, potentially with better documentation and less boilerplate.
  • We already have rand::random; if the above (inherent trait methods) happens I might even consider removing this.
  • We don't have Rng::choose and Rng::shuffle because they are redundant with the slice/iterator variants, but with inherent methods on ThreadRng this might actually make sense (enabling rand::thread_rng.shuffle(&mut my_vec)).

Thus I think we should probably reject this PR.


In my mind, the case for these others is less compelling:

  • fill: The most common use case might be generating 128-bit or 256-bit seeds/keys, but random() already works for arrays up to size 32.

fill and random are not equivalent for byte-arrays (#1282).

@oconnor663
Copy link
Author

I put a wall of text on the issue thread 😅

@dhardy dhardy added the P-postpone Waiting on something else label Sep 9, 2024
@dhardy dhardy mentioned this pull request Sep 10, 2024
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P-postpone Waiting on something else
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants