---
title: "Reusable Laws for a Vector Protocol"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Reusable Laws for a Vector Protocol}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
knitr::read_chunk(
  system.file("examples", "vector-laws.R", package = "s7contract")
)
```

```{r setup}
library(S7)
library(s7contract)
```

The same four laws test ordinary double vectors and an S7 `ReadDepth` class.
For an introduction to interfaces and traits, see
[Behavioral Contracts on S7](s7-interfaces-and-traits.html).

## Vector-like behavior

Many algorithms need only a length, a way to slice, and access to values. Both
ordinary double vectors and `ReadDepth` objects implement those operations.
The class validator keeps positions and depths aligned, while the interface
describes the behavior consumers need.

```{r vector-interface}
```

A function can depend on this small protocol without knowing how the object is
represented internally.

```{r vector-consumer}
```

## One protocol, several implementations

A protocol author can publish a function returning a named list of laws.
Implementation authors supply a constructor; the laws compare each result with
the reference values passed to that constructor.

The domain here is unnamed vectors of finite doubles between -10 and 10, with
positive, in-range integer indices. `gen_double()` expands its bounds with size
and shrinks toward zero. Empty vectors and selections are included; indices may
repeat or appear out of order. The generator mixes ordered subsequences,
permutations without replacement, and repeated selections. Missing values,
names, and negative indices are outside this example.

`gen_bind()` constructs the object and an index generator from the reference
values. When those values shrink, it rebuilds both, preserving object validity
and index bounds. Bounds come from the reference data rather than the method
being tested. Inside the contract mask, `base::length()` keeps the reference
calculation separate from the interface's `length` alias.

```{r vector-law-suite}
```

`lapply()` runs the same four laws against both representations.

```{r vector-law-implementations}
```

## Which cases were tested?

The slicing law classifies inputs as empty or nonempty, records fractional
values, and labels repeated, reordered, subsequence, and permutation selections.
Labels describe the indices themselves, so they can overlap: an empty selection
is a subsequence, and a full ordered selection is also a permutation.
Each label counts once per accepted case.
Its `min_coverage` requirements use proportions: `reordered = 0.1` asks for
reordered indices in at least 10% of cases.

`gen_sample()` fixes cardinality and shrinks toward earlier source positions,
swapping selected positions to preserve uniqueness. `gen_subsequence()` grows
length with size and keeps source order during shrinking. Both sample positions;
equal values at different positions may still appear together. Sampling with
replacement uses `gen_vector()` and `gen_element()`.

```{r vector-law-coverage}
```

Fixing size at zero exercises only empty vectors. The predicate passes, but the
coverage requirements prevent the run from passing:

```{r vector-law-insufficient-coverage}
```

This follows the test-data classification discussed by
[Claessen and Hughes (2000), §2.4](https://users.cs.northwestern.edu/~robby/courses/395-495-2009-fall/quick.pdf).
These minima describe observed proportions within the chosen test budget;
they carry no statistical confidence guarantee. Discards, errors, and shrink
evaluations contribute no counts. A falsifying generated case does count, and
a run that ends early reports partial coverage alongside its primary failure.
See `new_law()` for classifier requirements and result fields.

## Structural conformance and a behavioral failure

This subclass inherits the correct length and value methods, but its slice
method reverses the requested order. All required methods are available, so
`implements()` succeeds. Its slices also have valid representations and the
expected value type and length.
This run uses integer-valued doubles to keep the counterexample easy to read.

```{r vector-law-broken}
```

Only the law about selected values and their order fails. The reduced input
still produces a valid slice, but its values differ from the reference slice.

```{r vector-law-counterexample}
```

The result records the inputs and run parameters needed to replay the failure:

```{r vector-law-replay}
```

## A bug hidden by integer inputs

This value method silently rounds fractional measurements. Integer-only inputs
let it pass; the same law with `gen_double()` detects the loss of precision.

```{r vector-law-rounding}
```

For generator composition, budgets, and tinytest integration, see
[Generative Laws with tinytest](property-laws.html).
