Recursive Quoted Language Expansion

Expands quoted language by recursively replacing any symbol that points to quoted language with the language it points to. The recursive process continues until only symbols that point to non-language objects remain. The resulting quoted language can then be evaluated normally. This differs from the traditional 'quote'/'eval' pattern because it resolves intermediate language objects that would interfere with evaluation.

Project Status: WIP - Initial development is in progress, but there has not yet been a stable, usable release suitable for the public.

Programmable Non-Standard Evaluation

Non-Standard Evaluation (NSE hereafter) occurs when R expressions are captured and evaluated in a manner different than if they had been executed without intervention. subset is a canonical example, which we use here with the built-in iris data set:

subset(iris, Sepal.Width > 4.1)
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 16          5.7         4.4          1.5         0.4  setosa
## 34          5.5         4.2          1.4         0.2  setosa

Sepal.Width does not exist in the global environment, yet this works because subset captures the expression and evaluates it within iris.

A limitation of NSE is that it is difficult to use programmatically:

exp.a <- quote(Sepal.Width > 4.1)
subset(iris, exp.a)
## Error in, exp.a): 'subset' must be logical

oshka::expand facilitates programmable NSE, as with this simplified version of subset:

subset2 <- function(x, subset) {
  sub.exp <- expand(substitute(subset), x, parent.frame())
  sub.val <- eval(sub.exp, x, parent.frame())
  x[! & sub.val, ]
subset2(iris, exp.a)
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 16          5.7         4.4          1.5         0.4  setosa
## 34          5.5         4.2          1.4         0.2  setosa

expand is recursive:

exp.b <- quote(Species == 'virginica')
exp.c <- quote(Sepal.Width > 3.6)
exp.d <- quote(exp.b & exp.c)
subset2(iris, exp.d)
##     Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
## 118          7.7         3.8          6.7         2.2 virginica
## 132          7.9         3.8          6.4         2.0 virginica

We abide by R semantics so that programmable NSE functions are almost identical to normal NSE functions, with programmability as a bonus.


  • Intro vignette for a more in depth introduction to oshka, including a brief comparison to rlang.
  • NSE Functions with oshka in which we recreate simplified versions of dplyr and data.table that implement programmable NSE with oshka::expand.


This package is proof-of-concept. If it elicits enough interest we will re-write the internals in C and add helper functions for common use patterns.

# or development version
devtools::instal_github('brodieg/[email protected]')

Feedback is welcome, particularly if you are aware of some NSE pitfalls we may be ignoring.



Brodie Gaslam is a hobbyist programmer based on the US East Coast.

The name of this package is derived from "matryoshka", the Russian nesting dolls.


oshka Release Notes


Initial CRAN release.

  • Shield both by class and by symbol name (to address :: and ::: issue brought up by @lionel-)


  • #1: Provide mechanism for shielding some elements from expansion.
  • #2: Function symbols substituted.
  • #5: Substitution now respects search path order.


Initial preliminary release. Some things might work.

Reference manual

It appears you don't have a PDF plugin for this browser. You can click here to download the reference manual.


0.1.2 by Brodie Gaslam, 2 years ago

Report a bug at

Browse source code at

Authors: Brodie Gaslam [aut, cre]

Documentation:   PDF Manual  

GPL (>= 2) license

Imports utils

Suggests knitr, rmarkdown, unitizer, covr

See at CRAN