Combinator naming principles
Before setting out on "The Great Combinator Renaming" :tm: we should document the naming principles.
Here's a cleaned up version distilled from past lessons in #223 and #243:
- Generator names should align with type names (
bool,char, ...list,option) - to be as predictable as possible - We should have short, unparameterized generators (
int,string, ...) to lower the barrier to entry - Specialized generators also start with the type name, but use a consistent suffix (
_pos,_neg,_size,_of, ...) as this will help find them, also when using tab-completion - We may include a few shorthand names for convenience (
int_pos->nat,option->opt, ...) - Overall we aim to be as consistent as possible, e.g., offering similar signatures across generator interfaces (
QCheck.Gen,QCheck.arbitrary,QCheck2.Gen)
We've already used these principles, e.g., in naming the bytes and string combinators in #245 as well as in #307 and #308,
so they should not come as a surprise.
Finally: I plan to add these naming principles to the documentation.
I've just opened #367 to address float names.
FTR, the unit and bool situation is consistent (it is admittedly also rather simple):
| Combinator name | QCheck.Gen | QCheck.arbitrary | QCheck2.Gen |
|---|---|---|---|
| unit | unit t | unit arbitrary | unit t |
| bool | bool t | bool arbitrary | bool t |
I've now opened #369 to address char names.
I've opened #370 to address option consistency.
For the result type the situation is nice, simple, and already consistent: 🥳
| Combinator name | Type signiture |
|---|---|
| QCheck.Gen.result | ?ratio:float -> 'a t -> 'e t -> ('a, 'e) result t |
| QCheck.result | ?ratio:float -> 'a arbitrary -> 'e arbitrary -> ('a, 'e) result arbitrary |
| QCheck2.Gen.result | ?ratio:float -> 'a t -> 'e t -> ('a, 'e) result t |
#371 took care of bytes renaming
I've just opened #372 to address string renaming
For int32 and int64 the situation is as follows:
| Combinator name | QCheck.Gen | QCheck.arbitrary | QCheck2.Gen |
|---|---|---|---|
| int32 | int32 t | int32 arbitrary | int32 t |
| ui32 | int32 t | - | int32 t |
| int64 | int64 t | int64 arbitrary | int64 t |
| ui64 | int64 t | - | int64 t |
As such their situation is reasonably consistent.
Furthermore
-
QCheck.Gen.ui32 -
QCheck2.Gen.ui32 -
QCheck.Gen.ui64and -
QCheck2.Gen.ui64
are already deprecated since 0.24 - and should be removed in our 1.0 release.
I've opened #373 with array renaming
and now #374 with list renaming
Good news! The tuple generators are consistent:
| Combinator name | QCheck.Gen | QCheck.arbitrary | QCheck2.Gen |
|---|---|---|---|
| pair | yes | yes | yes |
| triple | yes | yes | yes |
| quad | yes | yes | yes |
| tup2 | yes | yes | yes |
| tup3 | yes | yes | yes |
| tup4 | yes | yes | yes |
| tup5 | yes | yes | yes |
| tup6 | yes | yes | yes |
| tup7 | yes | yes | yes |
| tup8 | yes | yes | yes |
| tup9 | yes | yes | yes |
(I've left out the long type signatures though)
I've just opened a PR for int renaming: https://github.com/c-cube/qcheck/pull/376
Going over some of the remaining generator names, the situation for sized, fix, and delay generators is as follows:
| Combinator name | QCheck.Gen | QCheck.arbitrary | QCheck2.Gen |
|---|---|---|---|
| sized | 'a sized -> 'a t | - | 'a sized -> 'a t |
| sized_size | int t -> 'a sized -> 'a t | - | int t -> 'a sized -> 'a t |
| fix | (('a -> 'b t) -> ('a -> 'b t)) -> 'a -> 'b t | - | (('a -> 'b t) -> 'a -> 'b t) -> 'a -> 'b t |
| delay | (unit -> 'a t) -> 'a t | - | (unit -> 'a t) -> 'a t |
Generally, these are for more low-level generator manipulation, e.g., sized does not exist for QCheck.arbitrary.
As such it seems reasonable to leave them out of QCheck.arbitrary.
The situation is similar for the let operators:
| Combinator name | QCheck.Gen | QCheck.arbitrary | QCheck2.Gen |
|---|---|---|---|
| ( let+ ) | 'a t -> ('a -> 'b) -> 'b t | - | 'a t -> ('a -> 'b) -> 'b t |
| ( and+ ) | 'a t -> 'b t -> ('a * 'b) t | - | 'a t -> 'b t -> ('a * 'b) t |
| ( let* ) | 'a t -> ('a -> 'b t) -> 'b t | - | 'a t -> ('a -> 'b t) -> 'b t |
| ( and* ) | 'a t -> 'b t -> ('a * 'b) t | - | 'a t -> 'b t -> ('a * 'b) t |
It seems reasonable to keep it like this.
The subset and split are only present in QCheck.Gen:
| Combinator name | QCheck.Gen | QCheck.arbitrary | QCheck2.Gen |
|---|---|---|---|
| range_subset | size:int -> int -> int -> int array t | - | - |
| array_subset | int -> 'a array -> 'a array t | - | - |
| nat_split2 | int -> (int * int) t | - | - |
| pos_split2 | int -> (int * int) t | - | - |
| nat_split | size:int -> int -> int array t | - | - |
| pos_split | size:int -> int -> int array t | - | - |
Issue https://github.com/c-cube/qcheck/issues/238 tracks their addition to QCheck2.Gen and I'll leave it at that for now.
The situation for the generate* debug combinators is as follows:
| Combinator name | QCheck.Gen | QCheck.arbitrary | QCheck2.Gen |
|---|---|---|---|
| generate | ?rand:Random.State.t -> n:int -> 'a t -> 'a list | - | ?rand:Random.State.t -> n:int -> 'a t -> 'a list |
| generate1 | ?rand:Random.State.t -> 'a t -> 'a | - | ?rand:Random.State.t -> 'a t -> 'a |
| generate_tree | - | - | ?rand:Random.State.t -> 'a t -> 'a Tree.t |
Since there is no Tree.t type in QCheck this is reasonably consistent.
https://github.com/c-cube/qcheck/pull/380 addressed renaming of map combinators
I've just opened #381 for renaming of generator-returning shrink combinators