Skip to content

API Discussion: Combining Arbitraries #3

@jlink

Description

@jlink

Combining two or more arbitraries into a new one by using generated values from the individual arbitraries is a crucial capability when design more complex properties. Jqwik 1 has two approaches: Combinators and Builders.

For jqwik 2 I suggest to keep the Combinators approach but replace Builders with a more generic approach that allows to "sample" values from any available arbitrary and use it in creating a new one.

Combinators

Combine two or more arbitraries by providing a function that takes a value per arbitrary and uses the taken values to create another arbitrary. Example:

Arbitrary<String> names = ...;
Arbitrary<Integer> ages = ...;
Arbitrary<Person> people = Combinators.combine(names, ages)
                                      .as((name, age) -> new Person(name, age));

This is straightforward and seems to be intuitive to most developers.
Jqwik 1 defines combinator functions for up to 8 arbitraries.

Generic Sampling

Arbitrary<String> names = ...;
Arbitrary<Integer> ages = ...;

Arbitrary<Person> people = Sampler.use((Sampler sampler) -> {
	int age = sampler.draw(ages);
	String name = sampler.draw(names);
	return new Person(name, age);
});

This approach has two advantages:

  • It allows for any number of arbitraries to be used
  • It allwos for any number and nesting of combination steps

Mind that this approach cannot be implemented in Jqwik 1 due to how Jqwik 1 implements shrinking and randomized generation.

Discussion

In principle the Generic Sampling approach makes the Combinators approach redundant, because it's more powerful.
I'd still keep it, since combinators seem to be more intuitive and provide better discoverability.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions