| Title: | Behavioral Contracts and Generative Laws for 'S7' |
| Version: | 0.2.3 |
| Description: | Contract helpers built with 'S7' for expressing runtime protocols around ordinary 'S7' dispatch. Structural interfaces describe small sets of required 'S7' generics, while explicit traits record registered implementations with optional default methods and associated metadata. Optional runtime checks can validate argument and return specifications in contract-scoped evaluation. Generative laws combine generators, deterministic shrinking, and one-result 'tinytest' expectations. |
| License: | GPL (≥ 3) |
| Encoding: | UTF-8 |
| RoxygenNote: | 7.3.3 |
| Depends: | R (≥ 4.3.0) |
| Imports: | S7, stats |
| Suggests: | knitr, rmarkdown, tinytest |
| VignetteBuilder: | knitr |
| URL: | https://github.com/sounkou-bioinfo/s7contract, https://sounkou-bioinfo.github.io/s7contract/ |
| BugReports: | https://github.com/sounkou-bioinfo/s7contract/issues |
| NeedsCompilation: | no |
| Packaged: | 2026-09-09 19:23:30 UTC; sounkoutoure |
| Author: | Sounkou Mahamane Toure [aut, cre] |
| Maintainer: | Sounkou Mahamane Toure <sounkoutoure@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-09-09 19:50:02 UTC |
s7contract: Behavioral Contracts and Generative Laws for S7
Description
s7contract makes behavioral protocols explicit and testable around ordinary
S7 dispatch:
Details
Go-like structural interfaces defined by required generics.
Rust-like explicit traits with default methods and associated metadata.
Optional argument and return specifications checked at the point of use.
Property-based laws with integrated shrinking and tinytest expectations.
implements() checks method availability and has_trait() checks declared
implementation. check_law() tests behavior over generated cases. Protocol
authors can reuse laws across implementations by writing functions that
construct lists of laws; see vignette("protocol-laws").
new_state_law() tests sequences of commands against a reference model
with fresh fixtures.
Author(s)
Maintainer: Sounkou Mahamane Toure sounkoutoure@gmail.com
See Also
Useful links:
Report bugs at https://github.com/sounkou-bioinfo/s7contract/issues
Evaluate an S7 call under an interface or trait contract
Description
with(contract, expr) and expr %::% contract evaluate expr in a
contract mask. Required generics are shadowed by checking wrappers, so calls
to those generics use normal S7 dispatch while checking the optional argument
and return specifications stored in an interface requirement or trait method.
Only names resolved through the mask are checked; namespace-qualified calls
and calls inside separately defined helpers are not instrumented.
Usage
expr %::% contract
Arguments
expr |
An expression evaluated in a contract mask. Calls to generics named in the contract are checked. |
contract |
An interface created by |
Details
Checks force dispatch and typed arguments before the generic body runs.
Generic defaults retain their lexical scope and share ordinary R promises.
If a typed argument has only a method default, that default is evaluated
before dispatch and supplied to the generic. Such defaults should be pure
expressions of arguments and lexical bindings, without relying on method-body
locals or missing() for that argument.
Value
The value of expr, after any optional return check.
Examples
local({
draw <- S7::new_generic("draw", "x", function(x, color) {
S7::S7_dispatch()
})
Circle <- S7::new_class("TypedCircle", properties = list(r = S7::class_double))
S7::method(draw, Circle) <- function(x, color) paste(color, x@r)
Drawable <- new_interface(
"TypedDrawable",
generics = list(draw = interface_requirement(
draw,
args = list(color = S7::class_character),
returns = S7::class_character
))
)
with(Drawable, draw(Circle(r = 2), color = "red"))
checked_draw <- with(Drawable, function(x) draw(x, color = "red"))
checked_draw(Circle(r = 2))
draw(Circle(r = 2), color = "red") %::% Drawable
})
Compose dependent, sized, and recursive generators
Description
gen_bind() passes a generated value to bind, which constructs the next
generator. Shrinking first rebuilds that generator for smaller source values,
then shrinks its output. Each rebuild uses the same locally captured seed and
size, so random downstream draws remain reproducible regardless of shrink
traversal or random draws made by a law. The surrounding RNG state is restored
after each rebuild. Callbacks must not depend on external mutable state or
change the RNG configuration.
Usage
gen_bind(generator, bind, prototype = list())
gen_sized(factory, prototype = list())
gen_resize(generator, size)
gen_recursive(base, expand, prototype = list())
Arguments
generator, base |
A generator. |
bind |
Function of one generated value returning a generator. |
prototype |
Zero-length prototype of generated values, used when this
generator is an element of |
factory |
Function of one non-negative integer size returning a generator. |
size |
Non-negative integer size to use for every draw. |
expand |
Function accepting a child generator and returning a generator for one recursive layer. |
Details
gen_sized() passes the current size to a generator factory. gen_resize()
fixes the size used by one generator without changing its siblings.
gen_recursive() chooses between base and the generator returned by
expand(child). The supplied child recursively uses half the current size,
rounded down; size zero draws only from base. Shrinking tries the base
branch before shrinking the expanded value. Recursion through child
therefore terminates, provided callbacks themselves terminate and do not
introduce other recursion. Size bounds recursion depth, not total node count.
Value
An S7 generator object.
Examples
sized_vectors <- gen_bind(gen_integer(1L, 8L), function(n) {
gen_product(n = gen_constant(n), x = gen_vector(gen_integer(), n, n))
})
gen_example(sized_vectors)
trees <- gen_recursive(gen_constant(0L), function(child) {
gen_product(left = child, right = child)
})
gen_example(trees, size = 4L)
Generate and shrink model-valid command sequences
Description
Sequence length is sampled from zero through min(size, max). Generation
stops early if every command is unavailable. Available commands are selected
with equal probability. Generated inputs must satisfy their preconditions.
Usage
gen_commands(initial, commands, max = 10L)
Arguments
initial |
Initial model with value semantics. |
commands |
Non-empty list of descriptors made with |
max |
Maximum sequence length. |
Details
Shrinking removes contiguous chunks, then shrinks command inputs. Each candidate is replayed against the symbolic model: commands with unsatisfied preconditions or missing output references are removed, together with any commands that depend on them. Retained command IDs never change. Candidate construction is lazy and executes no implementation commands or fixtures.
Value
An S7 generator of lists of steps. Each step contains an integer id,
a command name, and its generated input.
Basic property-based test generators
Description
These generators carry their own deterministic shrink trees. Integer ranges and vector lengths expand with the runner's size. Integer values shrink toward zero when zero is within bounds, or toward the nearest bound. Product generators shrink one component at a time in argument order. Vector generators return an atomic vector only when the element prototype is atomic; those element draws must be scalar and match the prototype's storage type. Otherwise, vector generators return a list with one entry per element draw. Nested vector generators therefore return lists of vectors. Vector shrinking removes contiguous chunks, then shrinks individual elements, preserving the minimum length.
Usage
gen_constant(value)
gen_integer(min = -100L, max = 100L)
gen_map(generator, transform, prototype = list())
gen_product(...)
gen_vector(element, min = 0L, max = 10L)
Arguments
value |
Constant value to generate. |
min, max |
Inclusive integer bounds. For |
generator, element |
A generator. |
transform |
Function applied to generated values. |
prototype |
Zero-length prototype of mapped values. |
... |
Uniquely named generators. |
Value
An S7 generator object.
Examples
pairs <- gen_product(x = gen_integer(), y = gen_integer())
vectors <- gen_vector(gen_integer(), min = 0L, max = 8L)
Generate finite double values
Description
At size zero, gen_double() draws only origin. The bounds expand linearly
from the origin to min and max, reaching the full interval at size 100.
Larger sizes use that same interval. Use gen_resize() to sample the full
range at every runner size. Within the current bounds, generation interpolates
one uniform draw from stats::runif(). This samples a finite-precision
approximation to a continuous uniform distribution, not all representable
doubles uniformly. Bounds are inclusive constraints; endpoints are not
guaranteed to be drawn. Use gen_choice() with constants to target them.
Usage
gen_double(min = -100, max = 100, origin = NULL)
Arguments
min, max |
Finite scalar numeric bounds, with |
origin |
Finite scalar numeric shrink target within the bounds. |
Details
Shrinking tries the origin, then the midpoint between the origin and the generated value, then successive midpoints approaching that value. For example, 8 with origin 0 has children 0, 4, 6, 7, 7.5, and so on. Each child follows the same rule. Candidates remain between the origin and their parent; iteration stops when rounding prevents further progress. Children are built only when visited. Values close to zero can require many steps to shrink through subnormal doubles, so the runner's evaluation budget still applies.
NA, NaN, and infinities are excluded. Add them explicitly with
gen_choice() or gen_element(). Branch weights control generation and
branch order controls shrinking; zero-weight branches are excluded from both.
Value
An S7 generator with a double element prototype.
References
Haskell Hedgehog separates shrink origins from
size-dependent bounds
and uses fractional shrinking toward an origin.
The R Hedgehog manual
documents gen.unif() and mixtures with exceptional numeric values.
Examples
measurements <- gen_double(-10, 10)
gen_example(measurements, size = 100L)
# 80% finite draws; 5% each for NA, NaN, -Inf, and Inf.
numeric_values <- gen_choice(
measurements, gen_element(c(NA_real_, NaN, -Inf, Inf)),
prob = c(4, 1)
)
gen_example(gen_vector(numeric_values, max = 5L))
Choose values or generators
Description
gen_element() samples one element of a vector or list. gen_choice()
samples a generator and draws from it at the current size. All choices are
available at size zero. Both shrink toward earlier entries, then
gen_choice() shrinks within the selected generator. Zero-weight entries
are excluded from both generation and shrinking.
Usage
gen_element(values, prob = NULL)
gen_choice(..., prob = NULL)
Arguments
values |
Non-empty atomic vector or list of values. |
prob |
Optional finite non-negative sampling weights, one per entry, with at least one positive weight. |
... |
One or more generators, ordered from simpler to more complex. |
Value
An S7 generator object. gen_element() preserves an atomic input's
element prototype; list inputs use a list prototype. gen_choice() retains
a common prototype when all branches agree, otherwise it uses list elements.
Examples
bases <- gen_element(c("A", "C", "G", "T"))
nullable <- gen_choice(gen_constant(NA_integer_), gen_integer(), prob = c(1, 9))
gen_example(gen_vector(bases, min = 4L, max = 4L))
Inspect a generator or disable its shrinking
Description
gen_example() draws one value at a fixed size with a local seed, restoring
the caller's RNG kind and state on exit, as check_law() does. It does not
expand the shrink tree. gen_no_shrink() keeps generation unchanged but
removes all shrink candidates, including those carried by composed generators.
Usage
gen_example(generator, size = 10L, seed = 1L)
gen_no_shrink(generator)
Arguments
generator |
A generator. |
size |
Non-negative integer size. |
seed |
Integer seed for reproducible generation. |
Value
gen_example() returns one generated value. gen_no_shrink() returns
an S7 generator object with the original element prototype.
Examples
gen_example(gen_vector(gen_integer()), size = 5L, seed = 42L)
Sample source positions without replacement
Description
gen_sample() draws a uniform ordered sample of exactly size source
positions, without replacement. Its cardinality and sampling range do not
depend on the runner's size. The default draws permutations of the source.
Shrinking moves positions toward the beginning of the source, from left to
right. Each position tries the earliest position unused by its prefix, then
integer bisections toward its current position. Targets already in the prefix
are skipped; targets used later in the sample are swapped. Every child is
lexicographically smaller, with the same cardinality and distinct positions.
The terminal sample consists of the first size source entries in order.
Usage
gen_sample(values, size = length(values))
gen_subsequence(values, min = 0L, max = length(values))
Arguments
values |
An atomic vector or list, optionally named.
|
size |
Fixed non-negative sample cardinality, at most |
min, max |
Inclusive non-negative subsequence length bounds, with
|
Details
gen_subsequence() chooses a length uniformly between min and
min(max, min + runner_size), then samples that many positions and sorts
them. It shrinks length toward min first, rebuilding a sample with a captured
seed as in gen_bind(), then shrinks positions. Source order and length
bounds are preserved. Different position shrinks can yield the same sorted
subsequence. Setting min = max = length(values) yields a constant.
Uniqueness concerns positions, not values: duplicated source entries can
appear together. Subsetting with [ preserves names and supported classes;
values themselves are not shrunk. Empty sources allow only empty selections.
Both generators have a list prototype, so gen_vector() nests their results.
For sampling with replacement, compose gen_element() and gen_vector().
Value
An S7 generator.
References
R's sampling documentation
describes positional sampling and the hash algorithm used for small samples
from large populations. These generators use sample.int() without
constructing a vector of every source position.
The R Hedgehog manual
documents subsequences and sampling as distinct generator domains.
Examples
gen_example(gen_sample(letters, size = 3L))
gen_example(gen_subsequence(letters, max = 5L))
gen_example(gen_sample(seq_len(100000000L), size = 3L))
Inspect or check a Go-like structural interface
Description
Inspect or check a Go-like structural interface
Usage
interface_requirements(interface, inherited = TRUE)
interface_report(x, interface)
missing_requirements(x, interface)
implements(x, interface)
assert_implements(x, interface, arg = deparse(substitute(x)))
as_interface(x, interface)
Arguments
interface |
An interface created by |
inherited |
Include inherited requirements from parent interfaces? |
x |
An object, or an S7 class/base class wrapper. |
arg |
Name to use in error messages. |
Value
interface_requirements() returns a named list of
interface_requirement() objects. interface_report() and
missing_requirements() return data frames. implements() returns a single
logical value. assert_implements() and as_interface() return x,
unchanged.
Describe a command for a stateful protocol
Description
Commands separate the implementation's effects from a reference model.
generate(state) returns an input generator, or NULL when the command is
unavailable. execute(fixture, input) calls the implementation.
require(state, input) checks the symbolic precondition, and
ensure(state, input, output) checks the observed result against the model
before the command. Both predicates return one non-missing logical value.
Usage
new_command(
name,
generate,
execute,
ensure,
update = function(state, input, output) state,
require = function(state, input) TRUE
)
Arguments
name |
Non-empty command name, unique within a command set. |
generate |
Function of the model state returning a generator or |
execute |
Function of the fixture and resolved input returning an output. |
ensure |
Function of the previous state, resolved input, and output returning whether the postcondition holds. |
update |
Function of the previous state, input, and output returning the next state. Defaults to leaving the model unchanged. |
require |
Function of the symbolic state and input returning whether the
command is permitted. Defaults to |
Details
update(state, input, output) returns the next model. During generation and
shrinking, output is an opaque reference to this command's future result.
During execution it is the actual result. Updates may store and pass outputs
but must not inspect or compute with them. Expected values should come from
the model and inputs, independently of the implementation.
References may be passed as inputs directly or inside ordinary, unclassed
lists. They are resolved before execution, including references to NULL
outputs. References embedded in other objects are not traversed. Model values
must have value semantics: callbacks must not mutate shared environments or
other reference objects in the model. Generation, preconditions, and updates
must be pure apart from generator draws; preconditions and updates must not
draw random numbers.
Value
An S7 command descriptor, used by gen_commands() and
new_state_law().
Construct a property-based test generator
Description
A generator draws a value together with an integrated tree of smaller values.
new_generator() is the extension point for custom generators. Its draw
function receives a non-negative integer size and returns one value. Its
deterministic shrink function returns a list of strictly smaller values.
The custom shrinker constructs that list itself; the framework constructs
and transforms the corresponding tree nodes only as they are visited.
Usage
new_generator(
draw,
shrink = function(value) list(),
label = "custom",
prototype = list()
)
Arguments
draw |
Function of one |
shrink |
Function of one generated value that returns a list of smaller values. |
label |
Short description used in diagnostics. |
prototype |
Zero-length prototype used by |
Value
An S7 generator object.
Build a Go-like structural interface on top of S7
Description
new_interface() models the method-list part of Go interfaces as a list of
required S7 generics. An interface is just a named set of required generics,
and a class or object satisfies it when S7 can find a method for every
required generic.
Usage
new_interface(
name,
generics = list(),
parents = list(),
package = NULL,
methods = NULL
)
interface_requirement(
generic,
name = NULL,
args = list(),
returns = S7::class_any
)
Arguments
name |
For |
generics |
For |
parents |
Optional interface or list of interfaces to embed. |
package |
Optional package name used only for display. |
methods |
Compatibility alias for |
generic |
An S7 generic function. |
args |
Optional named list of S7 classes, interfaces, or traits for
runtime argument checking with |
returns |
Optional S7 class, interface, or trait for runtime return
checking with |
Details
This mirrors Go's basic interfaces defined only by methods. Define small interfaces at the point where consuming code needs a behavior. Define S7 classes, generics, and methods normally; then let consumers name the protocol they accept. Up-front interfaces are also useful for package protocols, abstract data types, or recursive protocols.
Go's full post-1.18 type-set language is outside this model, including tilde type terms, unions of concrete types, or pointer/value receiver rules.
Value
new_interface() returns an S7 object of class
s7_interface. interface_requirement() returns an S7 object of class
s7_interface_requirement.
Examples
local({
area <- S7::new_generic("area", "x")
draw <- S7::new_generic("draw", "x")
Circle <- S7::new_class(
"Circle",
properties = list(r = S7::class_double)
)
Rect <- S7::new_class(
"Rect",
properties = list(w = S7::class_double, h = S7::class_double)
)
S7::method(area, Circle) <- function(x) pi * x@r^2
S7::method(draw, Circle) <- function(x) sprintf("circle(r = %s)", x@r)
S7::method(area, Rect) <- function(x) x@w * x@h
Drawable <- new_interface("Drawable", generics = list(draw = draw))
Shape <- new_interface("Shape", generics = list(area = area), parents = Drawable)
implements(Circle, Shape)
missing_requirements(Rect, Shape)
})
Define and check a generative law
Description
A law is a named, universally quantified claim sampled over explicitly
supplied generators. check_law() is test-framework neutral and returns a
structured S7 result. expect_law() adapts that result to one tinytest
expectation, regardless of how many generated cases were checked.
Usage
new_law(
name,
generators,
holds,
classify = function(...) character(),
min_coverage = numeric()
)
assume(condition)
check_law(
law,
tests = getOption("s7contract.tests", 100L),
seed = getOption("s7contract.seed", 1L),
shrinks = getOption("s7contract.shrinks", 100L),
discards = getOption("s7contract.discards", 100L),
max_size = getOption("s7contract.max_size", 100L)
)
format_check_result(x)
expect_law(
law,
tests = getOption("s7contract.tests", 100L),
seed = getOption("s7contract.seed", 1L),
shrinks = getOption("s7contract.shrinks", 100L),
discards = getOption("s7contract.discards", 100L),
max_size = getOption("s7contract.max_size", 100L)
)
Arguments
name |
Non-empty description of the law. |
generators |
Uniquely named non-empty list of generators. |
holds |
Function accepting the generated arguments and returning one non-missing logical value. |
classify |
Function accepting the same generated arguments as |
min_coverage |
Named numeric vector of minimum proportions in |
condition |
Scalar logical precondition. |
law |
A law created by |
tests |
Number of passing cases required. |
seed |
Deterministic local random seed. The caller's RNG kind and state are restored after the run. |
shrinks |
Maximum number of candidate shrink evaluations. |
discards |
Maximum number of discarded generated cases. |
max_size |
Maximum size passed to generators. |
x |
A result returned by |
Details
Runs use Mersenne-Twister, Inversion normals, and Rejection sampling,
independently of the caller's RNG kind. Box-Muller callers are rejected before
any RNG state is changed because R does not expose their cached normal draw.
Replay requires unchanged generator/law code, run parameters, and compatible
R/package versions; generators and laws must not depend on external mutable
state or change the RNG configuration. The result's parameters list records
all run arguments except law, for use with do.call(check_law, ...).
Shrinking is an ordered search, not a guarantee of a global minimum. The
counterexample's minimal field holds the last accepted failing candidate on
that search path; candidates have no general size ordering. A result's
shrink_status is "complete" when no immediate child preserves the
failure, "budget" when the evaluation limit stopped the search (including
zero), "error" if constructing candidates failed, or "not_needed" when no
counterexample was found. A shrinking error or warning is stored separately
in shrink_condition; the original and last failing examples are retained.
Generator warnings and errors terminate the run with status "error".
Warnings or errors from holds are counterexamples.
Stateful laws created by new_state_law() additionally retain failure traces
in the counterexample's original_condition and condition fields. Callback
defects stop their shrink search, preserving any earlier false postcondition.
Optional classify labels each generated input before holds runs. Labels
count once per case whose outcome is a pass or a false postcondition, including
stateful postcondition failures. Discards, errors, and shrink candidates are
excluded. A classifier warning, error, or invalid return terminates the run
with status "error" before evaluating that case's law.
The result's coverage data frame contains label, count, proportion,
minimum, and met; coverage_cases is the denominator. Requirements for
unseen labels have count zero. Unrequested minima and their met values are
NA; with no accepted cases, proportions and all met values are also NA.
After the requested passing cases, unmet minima give status
"insufficient_coverage" and make expect_law() fail without a counterexample.
Falsification, error, and exhaustion retain their own statuses and report
partial coverage. Minima describe observed proportions within the test
budget, without a statistical confidence guarantee. Generator size and
preconditions can change the sampled distribution.
In a tinytest file, call tinytest::using(s7contract) before calling
expect_law(). This activates tinytest's supported extension capture so the
property run is recorded as one ordinary test result.
Value
new_law() returns an S7 law. check_law() returns an S7 check
result. expect_law() returns one tinytest result. assume() returns
invisibly when its condition is true and otherwise discards the case.
Examples
reverse_law <- new_law(
"reverse is involutive",
generators = list(x = gen_vector(gen_integer(), max = 8L)),
holds = function(x) identical(rev(rev(x)), x)
)
check_law(reverse_law, tests = 20L, seed = 1L)
Define a generative law for a stateful protocol
Description
Builds an ordinary law for check_law() or expect_law(). Each evaluation,
including every shrink candidate, calls setup() to obtain a fresh fixture
and teardown(fixture) once after successful setup. If setup itself fails,
it is responsible for releasing any partially acquired resources.
Usage
new_state_law(
name,
initial,
commands,
setup,
teardown = function(fixture) NULL,
max_commands = 10L,
classify = function(...) character(),
min_coverage = numeric()
)
Arguments
name |
Non-empty description of the law. |
initial |
Initial model with value semantics. |
commands |
Non-empty list of descriptors made with |
setup |
Function of no arguments returning a fresh implementation fixture. |
teardown |
Function of that fixture releasing its resources. |
max_commands |
Maximum generated sequence length. |
classify |
Function of the generated |
min_coverage |
Named minimum case proportions, as in |
Details
A false command postcondition falsifies the law. Unexpected callback errors
or warnings produce an error and stop shrinking. Cleanup failures do not
replace an established postcondition failure: they are recorded in its
cleanup_condition and stop shrinking. User callbacks must terminate; the
shrink budget counts candidate evaluations, not individual commands.
Counterexamples retain the original and reduced command sequences. Their
original_condition and condition describe the original and reduced
failures, with the failing step, command, callback phase, pre-command
model, resolved input, output, and execution trace. Trace entries
record the model before and after each completed command. Model and output
snapshots require value semantics; mutable output handles retain their usual
R reference semantics. Replay has the same requirements as check_law(),
and setup must reproduce the same initial implementation state.
Value
An S7 law accepted by check_law() and expect_law().
Examples
increment <- new_command(
"increment",
generate = function(state) gen_integer(0L, 5L),
execute = function(fixture, input) {
fixture$value <- fixture$value + input
fixture$value
},
update = function(state, input, output) state + input,
ensure = function(state, input, output) identical(output, state + input)
)
counter_law <- new_state_law(
"counter follows its model", 0L, list(increment),
setup = function() list2env(list(value = 0L), parent = emptyenv())
)
check_law(counter_law, tests = 20L, seed = 1L)
Build a Rust-like explicit trait on top of S7
Description
new_trait() adds a nominal contract registry on top of S7 dispatch. A class
only has the trait after impl_trait() records the implementation, even if
compatible S7 methods already exist. Registrations belong to the current
R session and the particular trait descriptor, not its display name. Reuse
the same descriptor for registration and checks; deserializing a descriptor
does not transfer its registrations.
Usage
new_trait(
name,
methods = list(),
parents = list(),
assoc_types = character(),
assoc_consts = list(),
package = NULL
)
trait_method(
generic,
default = NULL,
name = NULL,
args = list(),
returns = S7::class_any
)
Arguments
name |
For |
methods |
For |
parents |
Optional trait or list of supertraits. |
assoc_types |
Required associated type names, or a named list of default associated type values. |
assoc_consts |
Required associated constant names, or a named list of default constant values. |
package |
Optional package name used only for display. |
generic |
An S7 generic function. |
default |
Optional default implementation. If supplied, |
args |
Optional named list of S7 classes, interfaces, or traits for
runtime argument checking with |
returns |
Optional S7 class, interface, or trait for runtime return
checking with |
Details
This makes default methods and associated metadata practical, but the result remains a runtime R abstraction. It does not emulate Rust's compile-time trait bounds, coherence, orphan rules, or type-checked associated types.
Value
new_trait() returns an S7 object of class s7_trait.
trait_method() returns an S7 object of class s7_trait_method.
Examples
local({
area <- S7::new_generic("area", "x")
perimeter <- S7::new_generic("perimeter", "x")
Circle <- S7::new_class(
"Circle",
properties = list(r = S7::class_double)
)
Measurable <- new_trait(
"Measurable",
methods = list(
area = trait_method(area),
perimeter = trait_method(perimeter, default = function(x) NA_real_)
),
assoc_consts = c("UNITS")
)
impl_trait(
Measurable,
Circle,
methods = list(area = function(x) pi * x@r^2),
assoc_consts = list(UNITS = "unitless")
)
has_trait(Circle, Measurable)
trait_call(Measurable, "area", Circle(r = 2))
trait_assoc_const(Measurable, Circle, "UNITS")
})
Inspect or use a Rust-like explicit trait
Description
Inspect or use a Rust-like explicit trait
Usage
trait_methods(trait, inherited = TRUE)
impl_trait(
trait,
class,
methods = list(),
assoc_types = list(),
assoc_consts = list(),
replace = FALSE
)
trait_report(x, trait)
has_trait(x, trait)
assert_trait(x, trait, arg = deparse(substitute(x)))
trait_call(trait, method, x, ...)
trait_assoc_type(trait, x, name)
trait_assoc_const(trait, x, name)
Arguments
trait |
A trait created by |
inherited |
Include inherited methods from supertraits? |
class |
A concrete S7 class, S3 class wrapper, S4 class, or base class wrapper. Register union members separately. |
methods |
Named list of method implementations. Omitted trait methods use their default implementation when one is available. |
assoc_types |
Named list of associated type values. |
assoc_consts |
Named list of associated constant values. |
replace |
Replace an existing implementation record and silence warnings about visible S7 methods? |
x |
An object or class. |
arg |
Name to use in error messages. |
method |
Method name within the trait. |
... |
Additional arguments passed to the S7 generic. |
name |
Associated item name. |
Value
trait_methods() returns a named list of trait_method() objects.
impl_trait() returns the stored implementation record, invisibly.
trait_report() returns a one-row data frame. has_trait() returns a
single logical value. assert_trait() returns x, unchanged.
trait_call() returns the result of the underlying S7 generic.
trait_assoc_type() and trait_assoc_const() return the stored associated
item value.