Skip to contents

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

As of the 0.0.1 release it should be considered ‘experimental’.

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

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)

tryCatch(
    glue(letters),
    error = function(e) conditionMessage(e)
)
## [1] "`x` must be a character vector of length <= 1."

Relative timing benchmarks

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.0000000   100
##   paste0  2.628975  2.417261  1.691085  1.660777  1.680842  0.2319008   100
##    super  9.212898  8.263039  6.160767  6.311100  5.606316  3.5426248   100
##     glue 81.193463 70.585741 46.695115 47.335739 40.842526 12.5723968   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.652230  1.576810  1.473244  1.483684  1.393527 2.010994   100
##    super  2.877958  2.807014  2.568070  2.801890  2.481449 1.338481   100
##     glue 19.464076 18.265600 16.071341 16.656581 14.711170 9.645303   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 3.839726 3.726157 3.576701 3.618956 3.569012 1.805505   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.524147 1.5097542 1.494169 1.469748 1.479917 1.418028   100
##   paste0 1.000000 1.0000000 1.000000 1.000000 1.000000 1.000000   100
##    super 1.011280 0.9999359 1.005869 1.001659 1.003474 1.042515   100
##     glue 1.068944 1.0600638 1.063230 1.050927 1.043550 1.062091   100