-
Notifications
You must be signed in to change notification settings - Fork 150
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
make arbitrary generate full range of integers #240
Conversation
For the purpose of semantic versioning, this PR (or any like it) should be considered a breaking change, as code may have (unwittingly) depended on the fact that integers were |
There is also code wittingly using |
@bluss yep, intentional dependence on This PR adds one workaround (for now) in this crate, for a type that clearly needs it. There is another category of types, including A third category is for types that clearly should ignore For crates that define a type, implement
If you want to show me some code I'm breaking to give me a little perspective, I'm all ears. |
Good point about the I have no special reason to share this petgraph code (that should be trivial to port), but it uses Though I think that in the long run, I would prefer if users of quickcheck used To me it would make sense that this is more quickcheck specific. For example, |
Yeah, I agree that third party crates should be able to depend only on Quickcheck for randomness (at least in their respective implementations of It would make sense to wrap |
While formulating a previous response, I looked through the types that Arbitrary is implemented on in this crate and realized I might have some issues
|
This ensures the distribution will be uniform, rather than just close to uniform (because of problem values).
gen_range is exclusive of the max value in the range, but gen() includes all values in the range
@BurntSushi and/or @bluss I would appreciate guidance on what should happen to The basic options are
|
range.contains is unstable in rust 1.34, which is supported by this library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks so much for this PR and the thoughtful attention to detail. :-)
So firstly, I do kind of feel like this is the right direction to head in. It's definitely a breaking change, so this will require a semver breaking change release. But I'm fine with that.
With respect to Range
, it would seem like it should just delegate to its component types Arbitrary
impl, like it does today, no? Could you say more about why you were thinking differently? Same for SocketAddrV6
.
Floats, on the other hand, should probably be consistent with integers. Is there any way you might be willing to include that in this PR? I'd rather not merge it piecemeal since I'd rather do both changes in a single release. It would be a little crazy to ignore size for integers but not for floats!
@bluss What do you think? Are you okay with this general direction?
For For |
Interesting. I personally find |
As for |
Yeah, it would. I'll take a crack at it tomorrow. It seems like a fairly quick fix. |
I take it back. I experimented a bit, but I think to match user expectations, the distribution needs to generate numbers in |
At this point, I have addressed all the review I received so far. |
This PR now fixes #27 |
Are you waiting for me to resolve merge conflicts with a merge commit or rebase? Or is this waiting on @bluss? Whether it is or not, I think the float code could do with review. |
Please don't wait for me :) Thanks for working on good solutions |
@BurntSushi This PR is ready to be merged. I'm curious what you think of the log-uniform distribution for floats. |
Is there a published fork with this bug fixed? It's a deal-breaker. In the meantime, to those looking for a workaround, I advice to do something like this:
|
@cognivore this PR is being made from my personal fork, so you could use that for now, but I don't advise it. I have no plans to maintain a fork of quickcheck and I will probably delete my fork soon after this PR is merged (but may create a new fork to make additional changes). Regarding your workaround, if you're using quickcheck internally i.e. not exposing a struct that implements Arbitrary in the public API of a library, the following is nicer workaround in my opinion. Be careful not to use this workaround if your test function takes a let gen = StdThreadGen::new(usize::max_value());
let mut qc = QuickCheck::with_gen(gen);
qc.quickcheck(test_function as fn(u8, u8) -> TestResult); |
Any movement on this? I'd be happy to help get this merged if need be. |
Also interested in what's the status of this, is anything blocking merging it in? (3 out of 10 open issues are also directly related to this) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, this LGTM. I'll merge this via a rollup PR soon.
All right, I've managed to bring this into my rollup branch. Note that for the future, when submitting reasonably small patches like this, please keep them to a single commit and force push. Having 16 commits in this branch tracking every winding change along with merges of master into the branch made it a real pain to squash it down into one commit. With that said, thank you for sticking with this PR over such a long time period! Apologies for taking a long time to merge it. QuickCheck isn't high on my list of crates to maintain. |
@@ -1039,8 +1056,8 @@ impl Arbitrary for RangeFull { | |||
|
|||
impl Arbitrary for Duration { | |||
fn arbitrary<G: Gen>(gen: &mut G) -> Self { | |||
let seconds = u64::arbitrary(gen); | |||
let nanoseconds = u32::arbitrary(gen) % 1_000_000; | |||
let seconds = gen.gen_range(0, gen.size() as u64); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity, why did you change this to use gen.size()
? It was implemented this way before, but it seems like we should probably open up the range of durations generated too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this was an oversight and based on previous discussion, I think the criterion for whether a type respects gen.size()
should be whether there are practical (memory, speed or some other resource) limits which make ignoring gen.size()
impractical. Based on this criterion, Duration
should not respect gen.size()
. If you agree with this criterion, I could add it to the documentation for Arbitrary
.
This commit tweaks the Arbitrary impls of number types (integers, floats) to use the full range with a small bias toward "problem" values. This is a change from prior behavior that would use the `size` parameter to control the range of integers. In retrospect, using the `size` parameter this way was probably misguided. Instead, it should only be used to control the sizes of data structures instead of also constraining numeric ranges. By constraining numeric ranges, we leave out a huge space of values that are never tested. Fixes #27, Fixes #119, Fixes #190, Fixes #233, Closes #240
Aims to fix #119, #190 and #233. Changes the implementation of
Arbitrary
for numbers to ignore thesize
ofgen
, and instead pick uniformly from the entire range of the type.Todo:
Gen
'ssize()
in documentation