# super

## Overview

super is a fork / reimplementation of the glue package with a focus on efficiency and simplicity at a cost of flexibility.

- `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

    library(super)

### Simple concatenation

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

    #> [1] "foobaz"

### List-like input

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

    #> [1] "Mazda RX4 does 21 mpg."           "Mazda RX4 Wag does 21 mpg."
    #> [3] "Datsun 710 does 22.8 mpg."        "Hornet 4 Drive does 21.4 mpg."
    #> [5] "Hornet Sportabout does 18.7 mpg." "Valiant does 18.1 mpg."

### Trimmed output

    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)

    #> My name is Fred,
    #> my age next year is 50,
    #> my anniversary is 1991-10-12.

### Partially vectorised

Over embraced arguments

    head(glue("Item {LETTERS}"))

    #> [1] "Item A" "Item B" "Item C" "Item D" "Item E" "Item F"

But not over input strings (yet)

    glue(letters)

    #> `x` must be a character vector of length <= 1.

## Relative timing benchmarks

    library(microbenchmark)

### Simple concatenation

    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"
    )

    #> Unit: relative
    #>     expr       min        lq      mean    median        uq       max neval
    #>  sprintf  1.000000  1.000000  1.000000  1.000000  1.000000  1.000000   100
    #>   paste0  2.836661  2.590583  2.120857  2.294360  2.121540  1.550206   100
    #>    super  8.854809  8.203512  6.404605  7.296424  6.673285  2.245947   100
    #>     glue 73.586207 66.836393 50.447605 58.493122 51.859807 11.218727   100

### Data frame input

    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"
    )

    #> Unit: relative
    #>     expr       min        lq      mean    median        uq       max neval
    #>  sprintf  1.000000  1.000000  1.000000  1.000000  1.000000  1.000000   100
    #>   paste0  1.659651  1.593393  1.520196  1.524206  1.466060  1.216451   100
    #>    super  2.726097  2.639392  2.607647  2.589537  2.507347  2.255755   100
    #>     glue 17.672880 16.931698 16.167487 16.004685 15.223437 20.757720   100

### Trimmed output

    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"
    )

    #> Unit: relative
    #>   expr      min       lq     mean   median       uq      max neval
    #>  super 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000   100
    #>   glue 4.142515 3.911418 3.763997 3.817862 3.835196 1.625525   100

### 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.

    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"
    )

    #> Unit: relative
    #>     expr      min       lq     mean   median       uq      max neval
    #>  sprintf 1.315949 1.315905 1.280219 1.286472 1.253286 1.029561   100
    #>   paste0 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000   100
    #>    super 1.020899 1.021252 1.012460 1.012929 1.000928 1.014163   100
    #>     glue 1.126174 1.155097 1.173894 1.164373 1.206051 1.121786   100