Skip to content
library(glue)
library(ggplot2)
library(bench)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

Glue is advertised as

Fast, dependency free string literals

So what do we mean when we say that glue is fast? This does not mean glue is the fastest thing to use in all cases, however for the features it provides we can confidently say it is fast.

A good way to determine this is to compare its speed of execution to some alternatives.

  • base::paste0(), base::sprintf(): Functions in base R implemented in C that provide variable insertion (but not interpolation).
  • R.utils::gstring(): Provides a similar interface as glue, but uses ${} to delimit blocks to interpolate.
  • pystr::pystr_format()1, rprintf::rprintf(): Provide an interface similar to python string formatters with variable replacement, but not arbitrary interpolation.

Note: stringr::str_interp() was previously included in this benchmark, but is now formally marked as “superseded”, in favor of stringr::str_glue(), which just calls glue::glue().

Simple concatenation

bar <- "baz"

simple <- bench::mark(
  glue       = as.character(glue::glue("foo{bar}")),
  gstring    = R.utils::gstring("foo${bar}"),
  paste0     = paste0("foo", bar),
  sprintf    = sprintf("foo%s", bar),
  rprintf    = rprintf::rprintf("foo$bar", bar = bar)
)

simple |>
  select(expression:total_time) |>
  arrange(median)
#> # A tibble: 5 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 sprintf    721.08ns  772.1ns  1188771.        0B     0   
#> 2 paste0       1.39µs    1.5µs   627136.        0B     0   
#> 3 glue        93.44µs   99.2µs     9648.  141.56KB    10.3 
#> 4 gstring     216.8µs  228.3µs     4276.    2.46MB     6.11
#> 5 rprintf    273.86µs  284.5µs     3440.  504.02KB     4.05

# plotting function defined in a hidden chunk
plot_comparison(simple)

Beeswarm plot comparing execution times of simple string concatenation across glue, gstring, paste0, sprintf, and rprintf. sprintf and paste0 are fastest, followed by glue, then gstring and rprintf.

While glue() is slower than paste0 and sprintf(), it is twice as fast as gstring(), and rprintf().

Although paste0() and sprintf() don’t do string interpolation and will likely always be significantly faster than glue, glue was never meant to be a direct replacement for them.

rprintf::rprintf() does only variable interpolation, not arbitrary expressions, which was one of the explicit goals of writing glue.

So glue is ~2x as fast as the function (gstring()), which has roughly equivalent functionality.

It also is still quite fast, with over 8000 evaluations per second on this machine.

Vectorized performance

Taking advantage of glue’s vectorization is the best way to improve performance. In a vectorized form of the previous benchmark, glue’s performance is much closer to that of paste0() and sprintf().

bar <- rep("bar", 1e5)

vectorized <- bench::mark(
  glue    = as.character(glue::glue("foo{bar}")),
  gstring = R.utils::gstring("foo${bar}"),
  paste0  = paste0("foo", bar),
  sprintf = sprintf("foo%s", bar),
  rprintf = rprintf::rprintf("foo$bar", bar = bar)
)

vectorized |>
  select(expression:total_time) |>
  arrange(median)
#> # A tibble: 5 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 paste0       8.35ms   8.38ms     119.    781.3KB     4.17
#> 2 sprintf      8.39ms   8.46ms     117.    781.3KB     4.17
#> 3 gstring     11.33ms  11.43ms      84.3    1.53MB     4.22
#> 4 glue        12.62ms  12.96ms      76.7    2.29MB     6.58
#> 5 rprintf     28.76ms  29.03ms      32.2    3.05MB     4.60

# plotting function defined in a hidden chunk
plot_comparison(vectorized)

Beeswarm plot comparing execution times of vectorized string concatenation across glue, gstring, paste0, sprintf, and rprintf. The order is paste0, sprintf, gstring, glue, rprintf. glue's performance is very similar to gstring and rprintf is noticeably less performant than the rest.