What’s new in R 4.5.0?

[This article was first published on The Jumping Rivers Blog, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

R 4.5.0 (“How About a Twenty-Six”) was released on 11th April, 2025. Here we summarise some of the interesting changes that have been introduced. In previous blog posts we have discussed the new features introduced in R 4.4.0 and earlier versions (see the links at the end of this post).

The full changelog can be found at the r-release ‘NEWS’ page and if you want to keep up to date with developments in base R, have a look at the r-devel ‘NEWS’ page.

penguins

Who doesn’t love a new dataset?

One of the great things about learning R for data science is that there are a collection of datasets available to work with, built into the base installation of R. The Palmer Penguins dataset has been available via an external package since 2020, and has been added to R v4.5.0 as a base dataset.

This dataset is useful for clustering and classification tasks and was originally highlighted as an alternative to the iris dataset.

In addition to the penguins dataset, there is a related penguins_raw dataset. This may prove useful when teaching or learning data cleaning.

use()

If you have worked in languages other than R, its approach to importing code from packages may seem strange. In a Python module, you would either import a package and then use functions from within the explicit namespace for the package:

import numpy
numpy.array([1, 2, 3])
# array([1, 2, 3])

Or you would import a specific function by name, prior to its use

from numpy import array
array([1, 2, 3])
# array([1, 2, 3])

In an R script, we either use explicitly-namespaced functions (without loading the containing package):

penguins |>
 dplyr::filter(bill_len > 40)

Or we load a package, adding all its exported functions to our namespace, and then use the specific functions we need:

library("dplyr")
penguins |>
 filter(bill_len > 40)

The latter form can cause some confusion. If you load multiple packages, there may be naming conflicts between the exported functions. Indeed, there is a filter() function in the base package {stats} that is overridden when we load {dplyr} – so the behaviour of filter() differs before and after loading {dplyr}.

R 4.5.0 introduces a new way to load objects from a package: use(). This allows us to be more precise about which functions we load, and from where:

# R 4.5.0 (New session)
use("dplyr", c("filter", "select"))

# Attaching package: ‘dplyr’
# 
# The following object is masked from ‘package:stats’:
#
# filter
#

penguins |>
 filter(bill_len > 40) |>
 select(species:bill_dep)

# species island bill_len bill_dep
# 1 Adelie Torgersen 40.3 18.0
# 2 Adelie Torgersen 42.0 20.2
# 3 Adelie Torgersen 41.1 17.6
# 4 Adelie Torgersen 42.5 20.7
# 5 Adelie Torgersen 46.0 21.5
# 6 Adelie Biscoe 40.6 18.6

Note that only those objects that we use() get imported from the package:

# R 4.5.0 (Session continued)
n_distinct(penguins)
# Error in n_distinct(penguins) : could not find function "n_distinct"

A feature similar to use() has been available in the {box} and {import} packages for a while. {box} is a particularly interesting project, as it allows more fine-grained control over the import and export of objects from specific code files.

Parallel downloads

Historically, the install.packages() function worked sequentially – both the downloading and installing of packages was performed one at a time. This means it could be slow to install many packages.

We often recommend the {pak} package for installing packages because it can download and install packages in parallel.

But as of R 4.5.0, install.packages() (and the related download.packages() and update.packages()) are capable of downloading packages in parallel. This may speed up the whole download-and-install process. As described in a post on the R-project blog by Tomas Kalibera, the typical speed-up expected is around 2-5x (although this is highly variable).

C23

C23 is the current standard for the C language. Much of base R and many R packages require compilation from C. If a C23 compiler is available on your machine, R will now preferentially use that.

grepv()

For pattern matching in base R, grep() and related functions are the main tools. By default, grep() returns the index of any entry in a vector that matches some pattern.

penguins_raw$Comments |> grep(pattern = "Nest", x = _)
# [1] 7 8 29 30 39 40 69 70 121 122 131 132 139 140 163 164 193 194 199
# [20] 200 271 272 277 278 293 294 299 300 301 302 303 304 315 316 341 342

We have been able to extract the values of the input vector, rather than the indices, by specifying value = TRUE in the arguments to grep():

penguins_raw$Comments |>
 grep(pattern = "Nest", x = _, value = TRUE)
# [1] "Nest never observed with full clutch." 
# [2] "Nest never observed with full clutch." 
# [3] "Nest never observed with full clutch." 
# [4] "Nest never observed with full clutch." 
# [5] "Nest never observed with full clutch." 
# [6] "Nest never observed with full clutch. Not enough blood for isotopes."

Now, in R 4.5.0, a new function grepv() has been introduced which will automatically extract values rather than indices from pattern matching:

penguins_raw$Comments |>
 grepv(pattern = "Nest", x = _)
# [1] "Nest never observed with full clutch." 
# [2] "Nest never observed with full clutch." 
# [3] "Nest never observed with full clutch." 
# [4] "Nest never observed with full clutch." 
# [5] "Nest never observed with full clutch." 
# [6] "Nest never observed with full clutch. Not enough blood for isotopes."

Contributions from R-Dev-Days

Many of the changes that are described in the “R News” for the new release came about as contributions from “R Dev Day”s. These are regular events that aim to expand the number of people contributing code to the core of R. In 2024, Jumping Rivers staff attended these events in London and Newcastle (prior to “SatRDays” and “Shiny In Production”, respectively). Dev days are often attached to a conference and provide an interesting challenge to anyone interested in keeping R healthy and learning some new skills.

Trying out R 4.5.0

To take away the pain of installing the latest development version of R, you can use docker. To use the devel version of R, you can use the following commands:

docker pull rstudio/r-base:devel-jammy
docker run --rm -it rstudio/r-base:devel-jammy

Once R 4.5 is the released version of R and the r-docker repository has been updated, you should use the following command to test out R 4.5.

docker pull rstudio/r-base:4.5-jammy
docker run --rm -it rstudio/r-base:4.5-jammy

An alternative way to install multiple versions of R on the same machine is using rig.

See also

The R 4.x versions have introduced a wealth of interesting changes. These have been summarised in our earlier blog posts:

For updates and revisions to this article, see the original post

To leave a comment for the author, please follow the link and comment on their blog: The Jumping Rivers Blog.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)