Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

stable

The goal of stable is to provide type stability for R objects through a flexible rule system. It allows you to create data structures that enforce constraints on modifications, ensuring type safety and preventing unwanted changes to your data.

Installation

You can install the development version of stable from GitHub:

# install.packages("devtools")
devtools::install_github("moodymudskipper/stable")

Example

Here are some examples showing how to use stable to create type-safe data structures:

library(stable)

# Create a stable tibble with default rules, explicited here for convenience
x <- stable_tibble(
  a = 1, 
  b = "z",
  .rules = c(
    rule_bounded(),                      # can't expand with new elements
    everything() ~ rule_required(),      # can't remove elements
    everything() ~ rule_stable_ptype()   # elements must respect their prototype
  )
)

# These operations will fail due to the rules:
x$c <- 3        # Can't add new column (bounded)
#> Error in `rule$rule()`:
#> ! Can't create element `c`, the object is bounded.
x$b <- 1        # Can't change type (stable ptype)  
#> Error in `rule$rule()`:
#> ! `new[nms]` must be a vector with type:
#> 
#>   <stable<
#>     a: double
#>     b: character
#>   >>
#> 
#> Instead, it has type:
#> 
#>   <stable<
#>     a: double
#>     b: double
#>   >>
x$b <- NULL     # Can't remove column (required)
#> Error in `rule$rule()`:
#> ! Can't remove element `b`, it is required.

# This works - same type
x$a <- 2
x
#> # A tibble: 1 × 2
#>       a b    
#>   <dbl> <chr>
#> 1     2 z

Flexible Rule System

You can create custom rule combinations for different use cases:

# Atomic elements only, but flexible structure
x <- stable_tibble(
  a = 1, 
  b = "z", 
  .rules = everything() ~ rule_predicate(is.atomic)
)

x$c <- 3           # Works - atomic
x$d <- list(4)     # Fails - not atomic
#> Error in `rule$rule()`:
#> ! The object must satisfy to `is.atomic` at d

# Type casting for compatible types
x <- stable_tibble(
  a = 1.0, 
  b = "z", 
  .rules = where(is.double) ~ rule_cast()
)

x$a <- 2L  # Integer gets cast to double
x
#> # A tibble: 1 × 1
#>       a
#> * <dbl>
#> 1     2

Works with dplyr

Stable objects work seamlessly with dplyr and base operations (provided methods are implemented in the package!):

x <- stable_tibble(a = 1, b = "z")

# This works
x |> dplyr::mutate(a = 2)
#> # A tibble: 1 × 2
#>       a b    
#>   <dbl> <chr>
#> 1     2 z

# This fails (trying to remove required column)
x |> dplyr::mutate(b = NULL)
#> Error in `rule$rule()`:
#> ! Can't remove element `b`, it is required.

x |> transform(b = NULL)
#> Error in `rule$rule()`:
#> ! Can't remove element `b`, it is required.

Available Rules

  • rule_bounded(): Prevents adding new elements
  • rule_required(): Prevents removing elements (requires selection)
  • rule_immutable(): Prevents modifying elements (requires selection)
  • rule_stable_ptype(): Ensures elements maintain their vector prototype
  • rule_predicate(): Applies custom validation functions
  • rule_cast(): Automatically casts compatible types

Rule Selection

Rules can be applied to specific elements using tidyselect syntax:

  • everything() ~ rule_required(): Apply to all columns
  • where(is.numeric) ~ rule_immutable(): Apply to numeric columns only
  • c(col1, col2) ~ rule_predicate(is.positive): Apply to specific columns

Note on nesting and subsetting stable objects

We can nest stable objects, though it’s not always useful.

# we don't need nested tibble objects
x <- stable_tibble(
  a =1, 
  b = tibble(c = 3, d = 4),
)
x$b$c <- "a"

# but they don't hurt
x <- stable_tibble(
  a =1, 
  b = stable_tibble(c = 3, d = 4),
)
x$b$c <- "a"

x$b$c <- 2

In the latter case we have a redundancy of checks but we can subset a stable object. We might argue that subsetting a stable object should produce a stable object by fetching the appropriate rules. This might be feasible.

About

What the Package Does (One Line, Title Case)

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages