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 tonnes of impls for Rand. #148

Closed
wants to merge 1 commit into from
Closed

Add tonnes of impls for Rand. #148

wants to merge 1 commit into from

Conversation

clarfonthey
Copy link
Contributor

@clarfonthey clarfonthey commented May 13, 2017

I'm not sure how many of these we want, but I just looked through the list and implemented as many as I found appropriate. I'm more than happy to prune the PR of unwanted impls.

Range { start: end, end: start }
} else {
Range { start: start, end: end }
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Not exactly sure why you’d cut half of the range here. Range with end < start does make sense in some contexts and the type in question has no real requirements wrt ordering of start and end points within it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a fair point. I'll remove it.

Copy link
Contributor

Choose a reason for hiding this comment

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

@nagisa Wouldn't this cause issues with Range<usize> or similar types where (correct me if I'm wrong) start is expected to be less than end?

src/lib.rs Outdated
//! *all* possible values of the type, just to a reasonable amount. For example,
//! `rand::random::<f64>()` will never return `f64::NAN`, and will only return
//! a value in the range [0, 1). `Option<u8>` will have a 1/2 chance of being,
//! `None`, not 1/257.
Copy link
Contributor

Choose a reason for hiding this comment

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

It is widely accepted/known that floating point random numbers are generated in range 0 to 1. As for None, if you ignore the NonNull optimisation, it having a chance of ½ is uniform from the perspective of bit pattern, which is (discriminant, value).

@clarfonthey
Copy link
Contributor Author

I've removed the note in lib.rs and made Range include backwards ranges. Let me know if you need anything before this is merged.

@clarfonthey
Copy link
Contributor Author

Bumping this.

@alexcrichton alexcrichton added the F-new-int Functionality: new, within Rand label Jun 14, 2017

impl Rand for Ipv4Addr {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> Ipv4Addr {

Choose a reason for hiding this comment

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

rng.gen::<i8>() would prevent overflow

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ipv4Addr accepts u8s. This uses type inference.

Copy link
Member

Choose a reason for hiding this comment

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

Should this exclude certain special addresses perhaps, e.g. those ending in 0 or 255?

May be easiest and fastest to implement via looping on rejection.

@dhardy
Copy link
Member

dhardy commented Jul 28, 2017

I'm not sure how many of these we want

@clarcharr Why? The only example I've come across so far where you might want random values of arbitrary types is fuzzing, but as I pointed out elsewhere this is very unlikely to generate certain special values that should probably be tested, e.g. 0, and may not give a sensible distribution for some types (e.g. Option<u32> would be None half the time in the current implementation, which may or may not be appropriate). Actually, for fuzzing, the current generator yielding floats in the range [0, 1) is probably not appropriate. And as dbaupp pointed out, the current implementation for char will yield unassigned codepoints 3/4 of the time.

Personally I see no use for these "default generators". If there is some use, e.g. fuzzing, then a specific distribution could be used instead (rand::distributions::Fuzzing, or probably better, an implementation in a fuzzing crate). If you think otherwise, please add your thoughts to the crate evaluation thread.

@clarfonthey
Copy link
Contributor Author

@dhardy the main reason why I was thinking these were useful was for derive(Rand) and potentially generics over Rand. If it's not useful then the PR can be closed, but I mostly put these out there to see what the opinion on it was.

@dhardy
Copy link
Member

dhardy commented Jul 31, 2017

@clarcharr thanks for your input. It's not for me to decide whether to close this PR.

Some of these like PhantomData are fair enough, but for others like Ordering — if you used derive(Rand) with this, would you necessarily want a 1/3 chance of Ordering::Equal? Perhaps for some uses the exact distribution doesn't matter, I don't know (my experience is with stochastic simulations, where distribution very much does matter, and the required distribution isn't always the same either).

@clarfonthey
Copy link
Contributor Author

Bump; is this PR desired or should I just close it for now? I'm willing to update it based upon feedback, but I'm not sure what should be changed/removed at the moment.

Copy link
Member

@dhardy dhardy left a comment

Choose a reason for hiding this comment

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

Well, some stuff like Wrapping seems like it should be added IMO. Some of the distributions seem weird and some of those ranges could be huge (so one can't just iterate over a random range). Stuff like Box which allocates... well, I can't see a real reason why it shouldn't be there. Adding extra features to Config.toml I'm not keen on.

But mostly I'll just say: patience! The rand refactor stuff will take a while, and there's not so much point in finalising this bit yet, although there's also no real reason it can't go ahead I guess (with the caveat that it may have to change later).

impl Rand for Duration {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> Duration {
Duration::new(rng.gen(), rng.gen_range(0, 1_000_000_000))
Copy link
Member

Choose a reason for hiding this comment

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

I would suggest using an exponential distribution here

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 consider Duration to be very similar to any other integer type, and so uniform probability makes the most sense to me.

Copy link
Contributor

Choose a reason for hiding this comment

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

How often are you working with hundred million year durations?

Copy link
Member

Choose a reason for hiding this comment

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

@clarcharr that's a null argument considering there are many things people might want to do with random integers (virtual dice, randomised network delays, random sorting, random selection from a list (e.g. a set of Unicode glyphs, Poisson distributions) and probably none of them involve uniform sampling from a fixed range not specific to this use-case.

I suggested exponential here because that, or sampling from a short arbitrary range (e.g. 0 to 1 minutes) are about the only things that make any sense whatsoever when you don't know the target use.

match rng.gen_range(0, 3) {
0 => Ordering::Less,
1 => Ordering::Equal,
2 => Ordering::Greater,
Copy link
Member

Choose a reason for hiding this comment

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

1/3 chance of each ordering may be okay, but it's arbitrary and even weird. Not really sure; it's not worse than any other option but may still not be what's wanted. Still, we already have 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.

Fair! I was considering this for the sake of testing, and IMHO each should be equally likely to be tested.

impl<T: Rand + PartialOrd> Rand for Range<T> {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> Range<T> {
Range { start: rng.gen(), end: rng.gen() }
Copy link
Member

Choose a reason for hiding this comment

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

Don't we need to ensure end ≥ start ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See previous comments from @nagisa.


impl Rand for Ipv4Addr {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> Ipv4Addr {
Copy link
Member

Choose a reason for hiding this comment

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

Should this exclude certain special addresses perhaps, e.g. those ending in 0 or 255?

May be easiest and fastest to implement via looping on rejection.

#[inline]
fn rand<R: Rng>(rng: &mut R) -> Ipv6Addr {
Ipv6Addr::new(rng.gen(), rng.gen(), rng.gen(), rng.gen(),
rng.gen(), rng.gen(), rng.gen(), rng.gen())
Copy link
Member

Choose a reason for hiding this comment

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

Also, should any addresses be omitted here? No idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They're all valid addresses, even though many are not routable. So, IMHO this is correct.

Copy link
Member

@dhardy dhardy Oct 9, 2017

Choose a reason for hiding this comment

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

That's the problem with general implementations like this: you have no idea how they will be used. Given that special addresses are very rare and therefore unlikely to come up by accident, it seems sensible to specify that they won't come up at all.

}

// TODO: remove Copy
impl<T: Copy + Rand> Rand for Cell<T> {
Copy link
Member

Choose a reason for hiding this comment

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

I doubt you'll ever be able to remove Copy. So remove the TODO?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, doing so only requires a minimum rustc bump.

nightly = ["i128_support"]
bound = [] # std::collections is unstable in 1.0.0
duration = [] # Duration is unstable in 1.0.0
ip_addr = [] # IpAddr is unstable in 1.0.0
Copy link
Member

Choose a reason for hiding this comment

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

I'm not so keen on adding a bunch of conditional features here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed! These should be added properly with a rustc version bump.

@dhardy
Copy link
Member

dhardy commented Feb 10, 2018

All those interested: should we remove rand_derive? Comments in dhardy#83 please.

@pitdicker
Copy link
Contributor

pitdicker commented Mar 6, 2018

Now that Rand and rand-derive are deprecated, it seems to me almost all those impls for Rand do not make sense anymore. One that may still be desired are those for Wrapping<T>. Also Duration, but that is probably much better served by a range #82.

@clarcharr I know there have been many months while your PR has been sitting here. But now that we have a clear idea of the future of the Rand trait, would you still be willing to make the changes?

@dhardy
Copy link
Member

dhardy commented Mar 6, 2018

Agreed. If we still had rand_derive then the PhantomData and Box impls would also make sense, but without that they are pointless. This Duration impl I don't like. #82 and #168 cover the remaining extensions, so I'm going to close this PR.

@dhardy dhardy closed this Mar 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-new-int Functionality: new, within Rand
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants