Introducing rpp

Launching the rpp Project

Kirill Müller https://github.com/krlmlr (cynkra)https://cynkra.com , John Coene https://github.com/JohnCoene (Opifex)https://opifex.org , Joe Thorley https://github.com/joethorley (Poisson)https://www.poissonconsulting.ca , Antoine Fabri https://github.com/moodymudskipper (cynkra)https://cynkra.com , Mark Padgham https://github.com/mpadge (rOpenSci)https://ropensci.org/
2021-10-13

We are very pleased to announce the release of rpp, part of the R pre-processing project.

The long-term goal of the organisation is to add static type checking and other features to R, with zero cost at run time. Our approach consists of generating plain R code from a different representation. The rpp package in its current form is a working prototype of a pluggable system for code generation.

Use cases

R is a weakly-typed interpreted language: variables can hold objects of any type, there is no explicit compilation stage, and no checks are carried out during run time. This is great for interactive ad-hoc analysis, but can make complex projects more difficult to maintain and debug. In contrast, in strongly-typed languages, the type of each variable is declared beforehand. Adding a static type checking layer to R would make it easier to improve stability in complex projects. With preprocessing, this can be done with no cost at runtime.

Preprocessing R code enables a multitude of other things, such as:

The rpp package aims at providing a framework for implementing preprocessing at the source code level. Currently rpp transform code inline, ultimately it should generate R code from a parallel directory.

State

Currently the project is in its very early stage. We have a working prototype (that we’d love for you to try), and we are determined to see this forward.

Also note that this is to be a fully open-source project all of which will be release under an MIT license and to which you are more than welcome to contribute.

Let us introduce the basic mechanics before delving into where we want this project to go.

Installation

Install the rpp package from Github.

remotes::install_github("pre-processing-r/rpp")

Plugin System

Currently, rpp implements a plugin system that will remain in the long-term, although it is likely to change over time. As mentioned, preprocessing code enables numerous things, not all could be implemented by a handful of people: the plugin system is there to empower other R users to create their own extensions.

There are currently two plugins available.

typed

Some of you may already know the typed package by Antoine Fabri (contributor to this project). This package implements dynamic type checks on R code. The problem of dynamic types is that they impact performance as these evaluated at run time.

There is now a typed plugin for rpp so that one can toggle the dynamic type checks on and off in a single line: keep them on while you develop, switch them off before pushing to prod.

remotes::install_github("pre-processing-r/typed")

chk

The chk package developed by Joe Thorley (contributor to this project) allows checking the types of user-supplied arguments.

These are also evaluated at runtime. Using the newly added rpp plugin one can now toggle these on and off so as not to impact performance in production but nonetheless run the checks while testing and developing.

remotes::install_github("pre-processing-r/chk")

Using Plugins

Currently rpp only supports working with R packages. Once the packages are installed add them to the Imports, either manually editing the DESCRIPTION or with usethis, eg.:

usethis::use_packages("typed", type = "Imports")

Also, add import(typed) to NAMESPACE, eg. via roxygen2 and #' @import typed in an .R source file.

Then, add the plugin call to the DESCRIPTION, for instance if using both typed and chk plugins add the following.

Config/rpp/plugins: list(typed::rpp_elide_types(), chk::rpp_elide_chk_calls())

In the future, if you want more plugins just add them to the list. Now, one is ready to use rpp.

Using rpp

As hinted at in the previous section the notion of “dev” and “prod” is at the core of rpp.

The idea is that, using rpp, one can toggle things on and off. This toggling happens between a “dev” and a “prod” state. Where one wants extra things to run, regardless of the impact on performance, in “dev” mode, but will want to remove such expensive computations in “prod.”

For instance, in an R package one can add a very simple function such as the one below—which depends on the typed package.

foo <- Character()? function(x = ?Character()) {
  Character()? out <- paste("foo:", x)
  out
}

This operates 3 checks:

It is useful while developing. The following will fail:

foo(1L)
Error: In `foo(1L)` at `check_arg(x, Character())`:
wrong argument to function, type mismatch
`typeof(value)`: "integer"  
`expected`:      "character"

Great! We can catch the error (the function expects a character string, not an integer). However, the type checking takes some computation time, albeit very little in this simple example, we may want to remove this check in production.

Simple, run rpp::rpp_to_prod(). The code for this function now looks like this:

foo <-              function(x               ) { # !q foo <- Character()? function(x = ?Character()) {
  out <- paste("foo:", x)                        # !q   Character()? out <- paste("foo:", x)
  out
}

The type checking logic is moved to comments, and replaced by plain R code. Whenever you want to switch back to the dev mode, run rpp::rpp_to_dev(). The roundtrip from dev to prod and back does not change the original code.

The production version is not particularly pretty, but does the job for now. Stay tuned for further developments in this project!

Citation

For attribution, please cite this work as

Müller, et al. (2021, Oct. 13). Pre-processing R code: Introducing rpp. Retrieved from https://rpreprocess.netlify.app/posts/2021-10-13-release/

BibTeX citation

@misc{müller2021introducing,
  author = {Müller, Kirill and Coene, John and Thorley, Joe and Fabri, Antoine and Padgham, Mark},
  title = {Pre-processing R code: Introducing rpp},
  url = {https://rpreprocess.netlify.app/posts/2021-10-13-release/},
  year = {2021}
}