Base slaps!


October 17, 2023


I gave a lightning talk at the NHS-R Conference 2023 about base R.


You can choose to watch the video on YouTube1.


The slides are embedded below2 or they can be opened in a dedicated tab. Click on them and press to advance, F to go fullscreen, and S to pop-out the speaker notes3.

The source is on GitHub. The slides are written with Quarto, of course.


The abstract for the talk:

Did you hear? Base R is dead! Or is it? I’ve spent most of my time in the public sector using the tidyverse, but I started learning R before the tidyverse existed (to be polite, you could call me ‘seasoned’). Recently I’ve started to write more base R code again. Why? I’ll talk about how base R can do loads of neat stuff out of the box without you needing to install and update any packages (dependencies aren’t bad things per se, but can cause trouble if not managed appropriately). I’ll also tell you about some recent additions, like the base pipe and lambda function notation, which demonstrate how base R is responding to the needs of the modern coder. Oh, and you can also do wacky stuff like make an interactive pixel-art creator, a persistent Tamagotchi pet, or a procedural dungeon-crawler. Note that this talk does not constitute a ‘base versus tidyverse’ flamewar. It’s purely to appreciate the elegance of good ol’ base R and to highlight some things it can do that you might not have realised (or like me, you forgot a long time ago).

In other words, the content of the talk was neither new nor earth-shattering4. The basic premise was ‘base R is pretty neat, don’t forget it exists!’

I have a narrow window of experience. I work in the public sector, mostly with people who publish statistical reports. The default for data preparation and analysis is often the tidyverse. That’s fine, for many reasons, but it may be overkill for small projects. Arguably, at worst, reproducibility may be jeopardised. And we love reproducibility in the public sector.

My plea to fellow public-sector coders: use your tool of choice, but consider if base R can do it alone5. Or, at very least, become more acquainted with the built-in functions and (spoiler alert) maybe build some off-piste packages for a laugh.


The talk mentions three beneficial things related to base R:

  1. Stability.
  2. Dependency.
  3. Modernity.

Re stability, vanilla R has changed little over time. Code written a couple of decades ago has a high chance of running now and will (likely) be executable for a long time into the future6. As a result, I contend that R is a horseshoe crab (unchanged for aeons, cryptically beautiful). And that R users are Milhouse in this relevant gif (look deep inside yourself, you are Milhouse).

Milhouse from the Simpsons pats a happy horseshoe crab on the head. Milhouse is not wearig his glasses. He thinks the crab is a dog.

Re dependencies, R’s extensibility is one of its greatest strengths, but reducing the dependency count could help improve reproducibility and reduce headaches7. I used an obligatory (adapted) xkcd comic to illustrate this. Note that base R is the literal, unyielding base of the teetering tower of packages used by your project (incredible metaphor).

Comic from xkcd. Lots of blocks are stacked on top of each other. One small block near the bottom is indicated. The implication is that removing the one small block will bring the whole thing down. The stack is labelled 'your project', the small block is labelled 'some dependency' and the big stable blocks underneath it at the bottom are labelled 'base'.

Re ‘modernity’, high stability hasn’t stopped base R from also being adapted to meet the expectations of a contemporary coder. R version 4.0 has given us a ‘modern base aesthetic’ (trademark pending) of pipes (|>), lambdas (\()) and string literals (r"{}"). R has morphed, much like the morphing of its janky old logo to the (perhaps already-outdated, lol) contemporary ‘flat’ design of the new logo8?

The old R logo morphs into the new R logo. The old has bevels, highlights and shadows. The new one is simpler with peak 'flat' design.

But wait! A bonus thing:

  1. ‘Oddity’.

Re oddity, base R has some hidden-gem functions that you can use for serious—or utterly nonserious things—like:

Despite all this, base R isn’t perfect for everyone in every situation9. Base flaps sometimes, that’s fine. You can argue it’s more terse and less readable than the verb-driven tidyverse, for example. But we have a duty in the public sector to think about long-term code survival. And high employee turnover rates mean we should perhaps default to the most vanilla tool.

I like base R for writing functions and code I want to live for a long time, for example. I use the tidyverse for everyday data wrangling.

But ultimately, I just wanted to do this terrible ‘base slaps’/‘slap bass’ pun, sorry. But also, I hear that zoomers say ‘slaps’ to mean ‘cool’. I think. Oh dear, this was a flimsy premise for a talk. Cringe-driven development?


Session info
Last rendered: 2023-11-28 23:20:58 GMT
R version 4.3.1 (2023-06-16)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Ventura 13.2.1

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0

[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: Europe/London
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
 [1] assertthat_0.2.1    digest_0.6.33       R6_2.5.1           
 [4] fastmap_1.1.1       xfun_0.41           magrittr_2.0.3     
 [7] glue_1.6.2          stringr_1.5.0       knitr_1.45         
[10] htmltools_0.5.6.1   rmarkdown_2.25      lifecycle_1.0.3    
[13] cli_3.6.1           vctrs_0.6.4         compiler_4.3.1     
[16] httr_1.4.7          vembedr_0.1.5       rstudioapi_0.15.0  
[19] tools_4.3.1         xaringanExtra_0.7.0 curl_5.1.0         
[22] evaluate_0.23       yaml_2.3.7          rlang_1.1.1        
[25] jsonlite_1.8.7      htmlwidgets_1.6.2   stringi_1.7.12     


  1. No Matt Dray presentation is complete without a ‘Dr Dre’ pun at beginning, lol. Only made funnier by my ongoing work with RAP (Reproducible Analytical Pipelines).↩︎

  2. I think there’ll be a video; I’ll link to it here when it’s released.↩︎

  3. Amusingly, these notes are absolutely not what I said in the talk itself, lol.↩︎

  4. Although at least one attendee’s mind was blown to discover that you can simultaneously assign and print an expression by wrapping it in brackets, like (x <- 1).↩︎

  5. But to be clear: I don’t think you should ‘just replace all your code with base R code’. There’s very few examples of where that would make sense. But is it worth importing all of {dplyr} if you just want to select(), filter() and mutate() a data.frame? Maybe, maybe not.↩︎

  6. Until we all switch to the Julia and/or Rust languages, amirite.↩︎

  7. Bearing in mind that tools like {renv}, Docker and Nix (thanks Bruno) can help coordinate dependencies. But that’s yet another tool to manage.↩︎

  8. I think this was incepted into my brain by Jeroen in the {magick} docs.↩︎

  9. See the wishlist that Henrik Bengtsson has been hosting.↩︎