---
title: "oshka - Recursive Quoted Language Expansion"
author: "Brodie Gaslam"
output:
    rmarkdown::html_vignette:
        toc: true
        css: styles.css

vignette: >
  %\VignetteIndexEntry{Introduction}
  %\VignetteEngine{knitr::rmarkdown}
  %\usepackage[utf8]{inputenc}
---

```{r global_options, echo=FALSE}
knitr::opts_chunk$set(error=TRUE, comment=NA)
library(oshka)
```

```{r child='./rmdhunks/basic.Rmd'}
```
```{r child='./rmdhunks/forwarding.Rmd'}
```

## Other Considerations

One drawback of the `eval`/`bquote`/`.()` pattern is that the actual objects
inside `.()` are placed on the call stack.  This is not an issue with symbols,
but can be bothersome with data or functions.  For example, in:

```{r, eval=FALSE}
my_fun_inner <- function(x) {
  # ... bunch of code
  stop("end")
}
my_fun_outer <- function(x) {
  eval(bquote(.(my_fun)(.(x))), parent.frame())
}
my_fun_outer(mtcars)
traceback()
```

The entire deparsed function definition and data frame will be displayed in
the traceback, which makes it difficult to see what is happening.  A simple
work-around is to use:

```{r, eval=FALSE}
sapply(.traceback(), head, 1)
sapply(sys.calls(), head, 1)  # sys.calls is similarly affected
```

## Versus `rlang`

`oshka` is simple in design and purpose.  It exports a single function that
substitutes expressions into other expressions.  It hews closely to R semantics.
`rlang` is more ambitious and more complex as a result.  To use it you must
learn new concepts and semantics.

One manifestation of the additional complexity in `rlang` is that you must
unquote expressions to use them:

```{r eval=FALSE}
rlang.b <- quo(Species == 'virginica')
rlang.c <- quo(Sepal.Width > 3.6)
rlang.d <- quo(!!rlang.b & !!rlang.c)

dplyr::filter(iris, !!rlang.d)
```

As shown earlier, the `expand` version is more straightforward as it uses the
standard `quote` function and does not require unquoting:

```{r rec_ex_1, eval=FALSE}
```

On the other hand, forwarding of NSE arguments to NSE functions is simpler
in `rlang` due to environment capture feature of quosures:

```{r eval=FALSE}
rlang_virginica <- function(subset) {
  subset <- enquo(subset)
  dplyr::filter(iris, Species == 'virginica' & !!subset)
}
```

Because `oshka` does not capture environments, we must resort to the
`eval`/`bquote` pattern:

```{r eval=FALSE}
oshka_virginica <- function(subset) {
  subset <- bquote(Species == 'virginica' & .(substitute(subset)))
  eval(bquote(.(subset2)(iris, .(subset))), parent.frame())
}
```

`oshka` minimizes the complexity in what we see as the most common use
case, and sticks to R semantics for the more complicated ones.

For additional discussion on `rlang` see the following presentations:

* [Tidyeval useR 2017 Presentation][1]
* [Tidy Evaluation (Hygienic fexprs)][2]

[1]: https://schd.ws/hosted_files/user2017/43/tidyeval-user.pdf
[2]: https://www.r-project.org/dsc/2017/slides/tidyeval-hygienic-fexprs.pdf
