---
title: "super"
output:
    html:
        meta:
            css: ["@default@1.13.67", "@callout@1.13.67", "@article@1.13.67"]
            js: ["@sidenotes@1.13.67", "@copy-button@1.13.67", "@callout@1.13.67", "@toc-highlight@1.13.67"]
        options:
            toc: true
            js_highlight:
                package: prism
                version: 1.29.0
        
vignette: >
  %\VignetteEngine{litedown::vignette}
  %\VignetteIndexEntry{super}
  %\VignetteEncoding{UTF-8}
  %\VignetteDepends{microbenchmark, glue}
---

```{r, include = FALSE}
litedown::reactor(print = NA)
```

## Overview

super is a fork / reimplementation of the [glue](https://glue.tidyverse.org)
package with a focus on efficiency and simplicity at a cost of flexibility.

::: {.callout-important data-legend="Differences from glue"}

- `super::glue()` takes only two arguments: A character string that is used as 
  a template and an environment to look up the embraced inputs. There is no
  option to change the delimiters from being a pair of braces (e.g. `{name}`).

- Embraced inputs are always looked up in the provided environment (akin to
  calling `get()`) and are not evaluated. This is similar to `glue::glue_safe()`
  and `glue::glue_data_safe()` but note that this is not the default behaviour
  of `glue::glue()`.
  
- `super::glue()` does not trim inputs. Instead this is done by either the
  function `super::glut()` or explicitly by `glue(trim(x))`.
  
- `super::glue()` returns an unclassed character vector whereas `glue::glue()`
  returns a `<glue>` object and provides a variety of methods to work on that
  object.
  
- At present, `super::glue()` does not provide any allowance for different
  handling of `NA` and `NULL` values, instead following the behaviour of
  `paste()`.
  
- Recycling of embraced arguments currently follows standard R recycling rules
  where the arguments will be recycled to the length of the longest one.
  
- `glue::glue()` arguments (and their associated behaviours) `.comment`,
  `.literal` and `.transformer` are not implemented.
  
:::
  
## Examples

```{r}
library(super)
```

### Simple concatenation

```{r}
bar <- "baz"
glue("foo{bar}")
```

### List-like input

```{r}
dat <- head(cbind(car = rownames(mtcars), mtcars))
glue("{car} does {mpg} mpg.", dat)
```

### Trimmed output
```{r}
name <- "Fred"
age <- 50
anniversary <- as.Date("1991-10-12")
out <- glut("
    My name is {name},
    my age next year is {age},
    my anniversary is {anniversary}.
")
cat(out)
```

### Partially vectorised

Over embraced arguments
```{r}
head(glue("Item {LETTERS}"))
```

But not over input strings (yet)

```{r, error=TRUE}
glue(letters)
```

## Relative timing benchmarks

```{r}
library(microbenchmark)
```

### Simple concatenation

```{r}
bar <- "baz"
bob <- 20

microbenchmark(
    sprintf    = sprintf("foo%s %d", bar, bob),
    paste0     = paste0("foo", bar, " ", bob),
    super   = super::glue("foo{bar} {bob}"),
    glue    = as.character(glue::glue_safe("foo{bar} {bob}", .trim = FALSE)),
    unit    = "relative",
    check   = "identical"
)
```

### Data frame input

```{r}
dat <- head(cbind(car = rownames(mtcars), mtcars))

microbenchmark(
    sprintf = with(dat, sprintf("%s does %.3g mpg.", car, mpg)),
    paste0  = with(dat, paste(car, "does", mpg, "mpg.")),
    super   = super::glue("{car} does {mpg} mpg.", dat),
    glue    = as.character(glue::glue_data(dat, "{car} does {mpg} mpg.")),
    unit    = "relative",
    check   = "identical"
)
```

### Trimmed output

```{r}
microbenchmark(
    super   = super::glut("
                  My name is {name},
                  my age next year is {age},
                  my anniversary is {anniversary}.
              "),
    glue    = as.character(glue::glue("
                  My name is {name},
                  my age next year is {age},
                  my anniversary is {anniversary}.
              ")),
    unit    = "relative",
    check   = "identical"
)
```

### Vectorized performance
For larger input with both `glue::glue()` and `super::glue()`, the performance
becomes dominated by the internally constructed call to `paste0()`, hence the
convergence observed below.

```{r}
bar <- rep("baz", 1e5)
microbenchmark(
    sprintf    = sprintf("foo%s %d", bar, bob),
    paste0     = paste0("foo", bar, " ", bob),
    super   = super::glue("foo{bar} {bob}"),
    glue    = as.character(glue::glue_safe("foo{bar} {bob}", .trim = FALSE)),
    unit    = "relative",
    check   = "identical"
)
```