Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upRand crate revision (pre-stabilisation) #2106
Conversation
dhardy
added some commits
Aug 1, 2017
This comment has been minimized.
This comment has been minimized.
Lokathor
commented
Aug 14, 2017
•
|
There's no reason for RNGs to not also have an If we're going to have Obviously I support the simpler version of a As to using a If we're having userspace PRNGs thare are not CSPRNGs, then we should absolutely add the PCGen and Xoroshiro PRNGs. Xoroshiro is even faster than pcg, but it's got Edit: it's got some unfortunate trouble with the lowest bit, so we'd have to be sure to override next_bool or equivalent with that generator. |
This comment has been minimized.
This comment has been minimized.
Agreed
I think there still are lifetime problems actually, if you want
I think you mean the Bernoulli distribution.
Yeah, I do too now; it's simpler and all the distribution stuff is available anyway. Even the simpler version is redundant against
Sounds like you're not too familiar with the two
Sounds like a good plan to me. But I'm not sure everyone agrees, hence the question over splitting the crate into a minimal core and extras or not. Did you finish your last sentence BTW? |
This comment has been minimized.
This comment has been minimized.
Lokathor
commented
Aug 14, 2017
|
Whoops. Fixed. I will reply a little more when i have more time later. |
This comment has been minimized.
This comment has been minimized.
Lokathor
commented
Aug 14, 2017
No I'm talking about IntoIterator, the version that consumes an owned value. No lifetime issue because there's no lifetime because there's no reference. It's not something that will be used a whole lot, but it should be available if you have ownership and Rust doesn't allow orphan instances, so we'll have to include it in the crate.
Yeah, neat. This is good. Might want a name that people not familiar with math would recognize a little more, but that's fine. I guess you can just say in the rustdoc what it does.
I was thinking mostly about the existing rand::distributions::range::Range. Hadn't seen the latest range update in the strawman proposal, if they're different at this point. As much as I hate trait soup, looking at range2 just now it feels like a good justification for a mild amount of it. It's very similar to how I did ranges for a game project over the weekend. Though, in my case the ranges produce values across The important part that we should keep in mind is in how easy it is to make new range implementations if you don't have a macro doing it for you. The macro can simplify the eight integral types and two float types, but it clearly wouldn't know how to handle a brand new GLRGBColor type (which would be three f32 values, each somewhere in the |
This comment has been minimized.
This comment has been minimized.
newpavlov
commented
Aug 14, 2017
|
Regarding relation between This will allow us to keep As for splitting between crates, I personally think we should not keep algorithms in Small suggestion regarding pub trait SeedableRng: Rng {
type Seed;
fn reseed(&mut self, Seed);
fn from_seed(seed: Seed) -> Self;
} |
nrc
added
the
T-libs
label
Aug 15, 2017
This comment has been minimized.
This comment has been minimized.
You still need to implement Regarding Bernoulli and other small distributions, this is how I've done it before. Here we could make use of the I don't know if you want to use @newpavlov the What was your other point @newpavlov, put @newpavlov using an associated type means each PRNG can only be seeded from one type... probably a good idea actually. Also see @Lokathor's point about removing |
This comment has been minimized.
This comment has been minimized.
Lokathor
commented
Aug 15, 2017
•
With my limited trait-fu I only know how to implement impl Iterator for Rng {
type Item = u32;
fn next(&mut self) -> Option<Self::Item>{
Some(self.next_u32())
}
}but I do not know how to implement I at least know how to do it for specific structs that implement pub struct RngIter<T:Rng>(T);
impl <T:Rng> Iterator for RngIter<T>{
type Item = u32;
fn next(&mut self) -> Option<Self::Item>{
Some(self.0.next_u32())
}
}
// here, PCGen32 is a type that implements Rng
impl IntoIterator for PCGen32 {
type Item = u32;
type IntoIter = RngIter<PCGen32>;
fn into_iter(self) -> Self::IntoIter{
RngIter(self)
}
}And then I got stuck.
That sounds... overkill? In this specific case, you're always using the HalfOpen range deal, fn chance<R:Rng>(rng: &mut R, chance: f32) -> bool {
let roll: f32 = rng.gen();
roll < chance
}This is valid with the current
Merely an example to illustrate the fact that we have to have it be clear how you'd make new instances for new types. Saying "if you have a weird type that isn't really like a number you'll maybe have to make up stuff yourself" is totally a valid decision, as long as we write that down in the docs. |
This comment has been minimized.
This comment has been minimized.
|
Oh, you want an iterator which yields a stream of Using a trait is overkill when a simple function suffices? I guess. Does it matter? One of Rust's great strengths is that you don't pay for this kind of stuff, except via a tiny bit of compiler time. (In C++ you paid with your sanity when trying to understand compiler errors — Rust at least mostly fixed that. I don't know Haskell.) |
KodrAus
reviewed
Aug 15, 2017
| that implementing types are prefixed with `#[derive(Debug)]`, although in some | ||
| cases it adds requirements on internal values. | ||
|
|
||
| Is this useful? |
This comment has been minimized.
This comment has been minimized.
| These traits can be added in the future without breaking compatibility, however | ||
| they may be worth discussing now. | ||
|
|
||
| ### Creation of RNGs |
This comment has been minimized.
This comment has been minimized.
KodrAus
Aug 15, 2017
Contributor
Without understanding too much more, it feels out-of-scope for Rng to be dictating the way implementations are constructed. What's the motivation around new_from_rng?
This comment has been minimized.
This comment has been minimized.
dhardy
Aug 15, 2017
Author
Contributor
new_from_rng replaces impl Rand for XXX from the current crate; e.g. see doc for ChaChaRng.
This is currently used to construct RNGs from OsRng. Potentially it could also be used to construct RNGs from other PRNGs, but that's not always a good idea, and isn't used within the rand crate anywhere, so new_from_rng could be removed now that RNGs have new seeding from OsRng. This would remove a footgun but also remove functionality which might sometimes have a legitimate use (I've wanted to try making a deterministic parallel simulation a couple of times).
This comment has been minimized.
This comment has been minimized.
Lokathor
Aug 15, 2017
impl Rand for PRNG is pretty easy to understand, you use let mut newGen: Foo = rng.gen() and the generics take care of it. I'm not sure why you'd want to remove it exactly.
On the other hand, most PRNGs will also be SeedableRng, and any SeedableRng is likely to be seedable from some type that has a Rand instance. In that case you'd just write Foo::from_seed(rng.gen()) to get the same effect.
This comment has been minimized.
This comment has been minimized.
KodrAus
Aug 16, 2017
Contributor
Ah gotcha. Hmm, I'm in two minds about using a single trait for generating random values vs bootstrapping (is there a better term for that?) other generators.
At least it's a bit surprising to me on my first pass through the API. I like the idea of keeping those concepts separate by default, as the RFC suggests.
If we were going to stick with Rand for constructing these generators from another one then I think the docs should call out that pattern explicitly.
This comment has been minimized.
This comment has been minimized.
KodrAus
Aug 16, 2017
•
Contributor
So to clarify, I like removal of Rand, and by extension using it to build rngs.
I don't think we need to explicitly recommend generators follow a particular pattern and leave it up to the specific implementation to know what makes sense and what will be consistent with the generators provided by rand.
This comment has been minimized.
This comment has been minimized.
Lokathor
Aug 16, 2017
One thing that @dhardy said: you can put rustdoc on the methods of a trait implementation for a type, and when you look at that type's implementation list as you scroll down the page that rustdoc will appear on the correct methods. Im not sure if they meant something else by "Rust not allowing documentation of impls" or not.
This comment has been minimized.
This comment has been minimized.
dhardy
Aug 17, 2017
•
Author
Contributor
let mut newGen = NewGenType::from_seed(oldGen.gen());
I suspect this won't work for many RNGs: the implementations of SeedableRng for ISAAC and ChaCha take a slice to seed from. Slices don't have a specified length in the type (like for example [u8; 4] does) and are not implemented directly by Rand or equivalent.
This comment has been minimized.
This comment has been minimized.
Lokathor
Aug 17, 2017
I suspect this is how the coding session would go if that error came up:
let mut newGen = NewGenType::from_seed(oldGen.gen());Compilation error? What the crap? Fine, Rust, if you want to be difficult I'll spell it out for you.
let seed: [u8;10] = oldGen.gen();
let mut newGen = NewGenType::from_seed(seed);Ha, look, I'm smarter than a compiler.
The point is that if a user gets it into their head to make a generator from a generator, they're going to fight to do that more than they're going to look up in some docs somewhere why that's not a good idea. And if array10 (or whatever size) doesn't have a random instance then they'll make an array with zeroed and fill that up using a loop. They'll do whatever it takes to get the job done more than they'll stop and reconsider. This happens all the time with programmers, and this happens more often with people that are new to a field/library/problem domain/etc. because the person doesn't understand they they have an XY Problem on their hands.
It's just human nature, and you can't really fix it, but you can anticipate it and plan for it by making sure that the path of least resistance for this sort of obstinate scenario is one that's actually a safe solution.
This comment has been minimized.
This comment has been minimized.
dhardy
Aug 17, 2017
Author
Contributor
Why would someone find SeedableRng::from_seed but not NewGenType::from_rng, when they are trying to create a NewGenType?
This comment has been minimized.
This comment has been minimized.
Lokathor
Aug 17, 2017
I agree with you that we should suggest from_rng be made when possible. KodrAus was the one against the idea of even suggesting that. Sorry for the confusion there.
This comment has been minimized.
This comment has been minimized.
Lokathor
commented
Aug 15, 2017
|
Oh! Ha, an As to traits compared to simple functions: I don't mean that there is a runtime cost on the program's execution speed, I mean that there is a cognitive cost to the programmer. Every element of a program should be exactly as simple as possible for it to accomplish its task. "A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away.", and all that sort of stuff. Last week we had this blog post in the news, and it's pretty much all true. A library can be as clever and smart as it wants to be but it's useless when people can't actually understand it and use it. Libraries like |
This comment has been minimized.
This comment has been minimized.
It turns out that both ISAAC and ChaCha RNGs accept a slice for initialisation. A slice ( Regarding removing |
This comment has been minimized.
This comment has been minimized.
newpavlov
commented
Aug 15, 2017
•
Yes this one, I think that such approach is quite common, with
If I had in mind something like trait FeedableRng {
type Entropy;
fn feed_entropy(&mut self, entropy: Entropy)
}Not sure if |
This comment has been minimized.
This comment has been minimized.
|
@newpavlov @Lokathor what do you think of the following? Does it reduce cognitive load enough that using distributions is now okay? In the lib (feel free to suggest a new name): pub trait SampleFromRng {
fn sample<T, D: Distribution<T>>(&mut self, distr: D) -> T;
}
impl<R: Rng+?Sized> SampleFromRng for R {
fn sample<T, D: Distribution<T>>(&mut self, distr: D) -> T {
distr.sample(self)
}
}In user code: use rand::{thread_rng, SampleFromRng};
use rand::distributions::{Uniform, Range, Exp};
fn main() {
// use with a static Rng type:
let mut rng = thread_rng();
let _a: u32 = rng.sample(Uniform);
let _b = rng.sample(Range::new(-2, 15));
// or use with a dynamic Rng type:
let mut rng: &mut Rng = &mut thread_rng();
let _c = rng.sample(Exp::new(2.0));
}I guess we could add methods like |
This comment has been minimized.
This comment has been minimized.
newpavlov
commented
Aug 15, 2017
•
|
@dhardy |
This was referenced Oct 19, 2017
This comment has been minimized.
This comment has been minimized.
burdges
commented
Oct 27, 2017
|
Just another thought on error handling here: #2191 |
kennytm
referenced this pull request
Nov 21, 2017
Closed
consider for new epoch: rand::sample's API should not be infalible #46163
This comment has been minimized.
This comment has been minimized.
vitiral
commented
Nov 21, 2017
|
I'm requesting that |
This comment has been minimized.
This comment has been minimized.
arthurprs
commented
Nov 23, 2017
|
I did miss a lot of comments but I couldn't parse a conclusion from the rfc text. Did we reach a consensus regarding providing only opaque RNGs (std_rng, weak_rng, thread_rng, osrng,....) (stable across major versions)? |
This comment has been minimized.
This comment has been minimized.
|
Not really. There's some discussion here. There has also been quite a bit of talk about reproducible generators; these would obviously require names (e.g. |
This comment has been minimized.
This comment has been minimized.
arthurprs
commented
Nov 23, 2017
|
Thanks. IMHO we shouldn't expose anything named. StdRng and WeakRng can be seedable/reproducible anyway. |
This comment has been minimized.
This comment has been minimized.
|
They can't be reproducible without adding a major restriction: not being able to replace the implementations with better PRNGs in the future. |
This comment has been minimized.
This comment has been minimized.
arthurprs
commented
Nov 23, 2017
|
You can always guarantee they're stable across major versions. |
This comment has been minimized.
This comment has been minimized.
|
Isn't that what I just said above? But why? We've already got a proposal to replace Unless you mean allow breakage. But again why? Someone writes a scientific simulator, does an experiment, publishes a result, along with a link to let other people reproduce output. Someone else writes a game with procedurally generated maps. Symmetric encryption works the same way: permute using a fixed pseudo-random sequence (although obviously people select named CSPRNGs for that, like ChaCha20). Queue a major version update, and suddenly people have trouble reproducing the simulation result and players complain that their maps changed, and for no good reason. Reproducibility means guaranteeing to produce the same output. |
This comment has been minimized.
This comment has been minimized.
arthurprs
commented
Nov 23, 2017
•
|
I'm not sure were we are misunderstanding each other but let's try again. I wholeheartedly agree that reproducibility is important, so let's get that out of the way. I'm arguing that |
This comment has been minimized.
This comment has been minimized.
|
So you're suggesting a half-way house? Well I have argued elsewhere that That still leaves open what you suggest, not having named generators like Sorry, been through this several times but too lazy to find the links because most of it is buried in the middle of a long comment thread like this one. Much better if you could open an issue to discuss stuff like this. |
This comment has been minimized.
This comment has been minimized.
Lokathor
commented
Nov 23, 2017
|
@arthurprs In the world of Rust, going from 0.x to 1.x is usually seen as the last breaking change you should ever make. The mentality is that you should never need to go to 2.x, and certainly not for at least a few years after 1.x came out. |
This comment has been minimized.
This comment has been minimized.
|
@Lokathor there are significant disagreements whether Rust 2.x should ever exist. And while it would be feasible to release |
This comment has been minimized.
This comment has been minimized.
arthurprs
commented
Nov 23, 2017
|
@dhardy Yes. If the user have a stronger reason to get algorithm X it can just use its crate. Consider WeakRng for example, there were almost half a dozen proposals to improve it. One can argue that the initial choice wasn't the best but its bound to happen again. If that kind of thing happen again the maintainers will have 3 choices (assume the PR has merits):
Note that 2 and 3 are potentially duplicating something from crates.io anyway, but with a blessing. |
This comment has been minimized.
This comment has been minimized.
|
@arthurprs what you say makes sense, so long as (a) the external crates aren't huge and (b) the external crates are sufficiently trustworthy (e.g. it may not be desirable to include a crate from an unknown author). But this is an important issue, and one I've already stepped around. Can you make a new issue to summarise please? (Easier for others to read.) |
This comment has been minimized.
This comment has been minimized.
Lokathor
commented
Nov 23, 2017
|
dhardy I was trying to agree with you and somehow you still ended up disagreeing with me ?_? |
This comment has been minimized.
This comment has been minimized.
|
@Lokathor sorry; I frequently disagree with everyone ;-) No offence intended there; I like to break arguments down into small enough pieces that we can work out what we do/don't agree on :-) |
This comment has been minimized.
This comment has been minimized.
Lokathor
commented
Nov 23, 2017
|
Since
|
This comment has been minimized.
This comment has been minimized.
It could be implemented as a method that adds entropy, rather than replacing it. |
This comment has been minimized.
This comment has been minimized.
Lokathor
commented
Nov 23, 2017
|
That would be some entirely other trait. |
This comment has been minimized.
This comment has been minimized.
|
We already have an issue on seeding RNGs: dhardy/rand#18 |
pitdicker
referenced this pull request
Jan 5, 2018
Closed
Distributions: Uniform, Uniform01, Open01, etc. #81
This comment has been minimized.
This comment has been minimized.
|
I'm closing out this RFC, as work is instead happening directly in the |
dhardy commentedAug 14, 2017
•
edited
Summary
Evaluate options for the future of
randregarding both cryptographic andnon-cryptographic uses.
There is a strawman revision which implements or demonstrates many of the changes
suggested in this document, but is not entirely in-sync with the suggestions
here.
Most current work is going on in the issue tracker and pull requests on this fork.
rand-coreRFC (subset; intended to be merged first)