Shrinkers should be able to provide a Stream
Opened this issue · 5 comments
Most List implementation (in particular, all from the JDK) are strict, meaning we may spend time building shrinks that will never even be tested.
Java 8's Streams can be lazy, enabling library consumers to wrap their shrunk value computation inside some lazy structure (e.g. a Supplier), and Junit Quickcheck would only process values until one doesn't pass.
Ideally this should be done after #219 as it may change the way shrinking works.
@pholser What's your opinion on the public API of com.pholser.junit.quickcheck.generator.Generator#shrink
?
- Make a breaking API change by changing the return type from
List<T>
toStream<T>
: for existing library consumers, it would be as easy as appending.stream()
at the end of their shrinker and change the return type in the function.
- Main benefit: API stays clean and easy to understand
- Main drawback: consumers must apply a (minor) change to all their shrinkers.
- Provide both APIs (e.g. add
shrinkStream()
), and users can implement one or both. The shrinker could append the list results to the stream results (thus lazy results are considered before strict ones) and then shrink.
Default implementation forshrinkStream()
would return an empty stream:Stream.empty()
.
- Main benefit: backward compatible.
- Main drawback: double API, more complexity to understand for consumers.
I'm in favor of 1) since the consumer impact is minimal, and easy to explain in the documentation.
@sir4ur0n What do you think of option 3: same as option 2, but deprecate the List<T>
signature of shrink
? Idea being that we don't force generator writers to break right away, but gently nudge toward lazy shrink value generation.
I would imagine removing the List
version as 1.0 becomes available.
Sounds good. I'll try to give it a shot in the coming days.
Any idea/opinion about when 1.0 lands?