rlang 1.0.0
Major changes
This release focuses on the rlang errors framework and features
extensive changes to the display of error messages.
-
abort()now displays errors as fully bulleted lists. Error headers
are displayed with a!prefix. See
https://rlang.r-lib.org/reference/topic-condition-customisation.html
to customise the display of error messages. -
abort()now displays a full chain of messages when errors are
chained with theparentargument. Following this change, you
should update dplyr to version 1.0.8 to get proper error messages. -
abort()now displays function calls in which a message originated
by default. We have refrained from showing these calls until now to
avoid confusing messages when an error is thrown from a helper
function that isn't relevant to users.To help with these cases,
abort()now takes acallargument that
you can set tocaller_env()orparent.frame()when used in a
helper function. The function call corresponding to this environment
is retrieved and stored in the condition. -
cli formatting is now supported. Use
cli::cli_abort()to get
advanced formatting of error messages, including indented bulleted
lists. See https://rlang.r-lib.org/reference/topic-condition-formatting.html. -
New
try_fetch()function for error handling. We recommend to use
it for chaining errors. It mostly works liketryCatch()with a few
important differences.-
Compared to
tryCatch(),try_fetch()preserves the call
stack. This allows full backtrace capture and allowsrecover()
to reach the error site. -
Compared to
withCallingHandler(),try_fetch()is able to
handle stack overflow errors (this requires R 4.2, unreleased at
the time of writing).
-
-
The tidy eval documentation has been fully rewritten to reflect
current practices. Access it through the "Tidy evaluation" and
"Metaprogramming" menus on https://rlang.r-lib.org.
Breaking changes
-
The
.dataobject exported by rlang now fails when subsetted
instead of returningNULL. This new error helps you detect when
.datais used in the wrong context.We've noticed several packages failing after this change because
they were using.dataoutside of a data-masking context. For
instance thebyargument ofdplyr::join()is not data-masked.
Previouslydplyr::join(by = .data$foo)would silently be
interpreted asdplyr::join(by = NULL). This is now an error.Another issue is using
.datainsideggplot2::labs(...). This is
not allowed sincelabs()isn't data-masked. -
call_name()now returnsNULLinstead of"::"for calls of the
formfoo::bar.We've noticed some packages do not check for
NULLresults from
call_name(). Note that many complex calls such asfoo()(),
foo$bar()don't have a "name" and cause aNULLresult. This is
why you should always check forNULLresults when using
call_name().We've added the function
is_call_simple()to make it easier to
work safely withcall_name(). The invariant is thatcall_name()
always returns a string whenis_call_simple()returnsTRUE.
Conversely it always returnsNULLwhenis_call_simple()retuns
FALSE. -
is_expression()now returnsFALSEfor manually constructed
expressions that can't be created by the parser. It used to return
TRUEfor any calls, including those that contain injected objects.Consider using
is_call()or just remove the expression check. In
many cases it is fine letting all objects go through when an
expression is expected. For instance you can inject objects directly
inside dplyr arguments:x <- seq_len(nrow(data)) dplyr::mutate(data, col = !!x) -
If a string is supplied to
as_function()instead of an object
(function or formula), the function is looked up in the global
environment instead of the calling environment. In general, passing
a function name as a string is brittle. It is easy to forget to pass
the user environment toas_function()and sometimes there is no
obvious user environment. The support for strings should be
considered a convenience for end users only, not for programmers.Since environment forwarding is easy to mess up, and since the
feature is aimed towards end users,as_function()now defaults to
the global environment. Supply an environment explicitly if that is
not correct in your case. -
with_handlers(),call_fn(), andfriendly_type()are deprecated. -
The
actionargument ofcheck_dots_used(),check_dots_unnamed(),
andcheck_dots_empty()is deprecated in favour of the newerror
argument which takes an error handler. -
Many functions deprecated deprecated in rlang 0.2.0 and 0.3.0 have
been removed from the package.
Fixes and features
tidyeval
-
New
englue()operator to allow string-embracing outside of dynamic
dots (#1172). -
New
data_sym()anddata_syms()functions to create calls of the
form.data$foo. -
.datanow fails early when it is subsetted outside of a data mask
context. This provides a more informative error message (#804, #1133). -
as_label()now better handles calls to infix operators (#956,
r-lib/testthat#1432). This change improves auto-labelled expressions
in data-masking functions liketibble(),mutate(), etc. -
The
{{operator is now detected more strictly (#1087). If
additional arguments are supplied through{, it is no longer
interpreted as an injection operator. -
The
.ignore_emptyargument ofenexprs()andenquos()no longer
treats named arguments supplied through...as empty, consistently
withexprs()andquos()(#1229). -
Fixed a hang when a quosure inheriting from a data mask is evaluated
in the mask again. -
Fixed performance issue when splicing classes that explicitly
inherit from list with!!!(#1140, r-lib/vctrs#1170). -
Attributes of quosure lists are no longer modified by side effect
(#1142). -
enquo(),enquos()and variants now support numbered dots like
..1(#1137). -
Fixed a bug in the AST rotation algorithm that caused the
!!
operator to unexpectedly mutate injected objects (#1103). -
Fixed AST rotation issue with
!!involving binary operators (#1125).
rlang errors
-
try_fetch()is a flexible alternative to bothtryCatch()and
withCallingHandlers()(#503). It is also more efficient than
tryCatch()and creates leaner backtraces. -
New
cnd_inherits()function to detect a class in a chain of errors
(#1293). -
New
global_entrace()function, a user-friendly helper for
configuring errors in your RProfile. Call it to enrich all base
errors and warnings with an rlang backtrace. This enables
last_error(),last_warnings(),last_messages(), and
backtrace_on_errorsupport for all conditions. -
New
global_handle()function to install a default configuration of
error handlers. This currently callsglobal_entrace()and
global_prompt_install(). Expect more to come. -
The "Error:" part of error messages is now printed by rlang instead
of R. This introduces several cosmetic and informative changes in
errors thrown byabort():-
The
callfield of error messages is now displayed, as is the
default inbase::stop(). The call is only displayed if it is a
simple expression (e.g. no inlined function) and the arguments are
not displayed to avoid distracting from the error message. The
message is formatted with the tidyverse style (codeformatting
by the cli package if available). -
The source location is displayed (as in
base::stop()) ifcall
carries a source reference. Source locations are not displayed
when testthat is running to avoid brittle snapshots. -
Error headers are always displayed on their own line, with a
"!"
bullet prefix.
See https://rlang.r-lib.org/reference/topic-condition-customisation.html
to customise this new display. -
-
The display of chained errors created with the
parentargument of
abort()has been improved. Chains of errors are now displayed at
throw time with the error prefix "Caused by error:". -
The
print()method of rlang errors (commonly invoked with
last_error()) has been improved:- Display calls if present.
- Chained errors are displayed more clearly.
-
inform()andwarn()messages can now be silenced with the global
optionsrlib_message_verbosityandrlib_warning_verbosity. -
abort()now outputs error messages tostdoutin interactive
sessions, following the same approach asinform(). -
Errors, warnings, and messages generated from rlang are now
formatted with cli. This means in practice that long lines are
width-wrapped to the terminal size and user themes are applied.
This is currently only the case for rlang messages.This special formatting is not applied when
abort(),warn(), and
inform()are called from another namespace than rlang.
See https://rlang.r-lib.org/reference/topic-condition-formatting.html
if you'd like to use cli to format condition messages in your
package. -
format_error_bullets()(used as a fallback instead of cli) now
treats:- Unnamed elements as unindented line breaks (#1130)
- Elements named
"v"as green ticks (@rossellhayes) - Elements named
" "as indented line breaks - Elements named
"*"as normal bullets - Elements named
"!"as warning bullets
For convenience, a fully unnamed vector is interpreted as a vector
of"*"bullets. -
abort()gains a.internalargument. When set toTRUE, a footer
bullet is added tomessageto let the user know that the error is
internal and that they should report it to the package authors. -
abort(),warn(), andinform()gain abodyargument to supply
additional bullets in the error message. -
rlang conditions now have
as.character()methods. Use this generic
on conditions to generate a whole error message, including the
Error:prefix. These methods are implemented as wrappers around
cnd_message(). -
headerandfootermethods can now be stored as closures in
condition fields of the same name. -
cnd_message()gains aprefixargument to print the message with
a full prefix, includingcallfield if present and parent messages
if the condition is chained. -
cnd_message()gains aninheritargument to control whether to
print the messages of parent errors. -
Condition constructors now check for duplicate field names (#1268).
-
cnd_footer()now returns thefooterfield by default, if any. -
warn()andinform()now signal conditions of classes
"rlang_warning"and"rlang_message"respectively. -
The
bodyfield of error conditions can now be a character vector. -
The error returned by
last_error()is now stored on the search
path as the.Last.errorbinding of the"org:r-lib"
environment. This is consistent with how the processx package
records error conditions. Printing the.Last.errorobject is now
equivalent to runninglast_error(). -
Added
is_error(),is_warning(), andis_message()predicates (#1220). -
interrupt()no longer fails when interrupts are suspended (#1224). -
warn()now temporarily sets thewarning.lengthglobal option to
the maximum value (8170). The default limit (1000 characters) is
especially easy to hit when the message contains a lot of ANSI
escapes, as created by the crayon or cli packages (#1211).
Backtraces
-
entrace()andglobal_entrace()now log warnings and messages
with backtraces attached. Runlast_warnings()orlast_messages()
to inspect the warnings or messages emitted during the last command. -
Internal errors now include a winch backtrace if installed. The user
is invited to install it if not installed. -
Display of rlang backtraces in dynamic reports (knitted documents
and RStudio notebooks) is now controlled by the
rlang_backtrace_on_error_reportoption. By default, nothing is
displayed in interactive sessions. In non-interactive sessions, a
simplified backtrace is displayed instead of a full backtrace -
The
last_error()reminder is no longer displayed in RStudio
notebooks. -
A
knitr::sew()method is registered forrlang_error. This makes
it possible to consultlast_error()(the call must occur in a
different chunk than the error) and to set
rlang_backtrace_on_errorglobal options in knitr to display a
backtrace on error.If you show rlang backtraces in a knitted document, also set this in
a hidden chunk to trim the knitr context from the backtraces:options( rlang_trace_top_env = environment() )This change replaces an ad hoc mechanism that caused bugs in corner
cases (#1205). -
The
rlang_trace_top_envglobal option fortrace_back()now
detects when backtraces are created within knitr. If the option is
not set, its default value becomesknitr::knit_global()when knitr
is in progress (as determined fromknitr.in.progressglobal
option). This prevents the knitr evaluation context from appearing
in the backtraces (#932). -
Namespace changes are now emboldened in backtraces (#946).
-
Functions defined in the global environments or in local execution
environments are now displayed with a space separator in backtraces
instead of::and:::. This avoids making it seem like these
frame calls are valid R code ready to be typed in (#902). -
Backtraces no longer contain inlined objects to avoid performance
issues in edge cases (#1069, r-lib/testthat#1223). -
External backtraces in error chains are now separately displayed (#1098).
-
Trace capture now better handles wrappers of calling handler in case
of rethrown chained errors. -
Backtraces now print dangling srcrefs (#1206). Paths are shortened
to show only three components (two levels of folder and the file). -
The root symbol in backtraces is now slightly different so that it
can't be confused with a prompt character (#1207).
Argument intake
-
arg_match()gains amultipleargument for cases where zero or
several matches are allowed (#1281). -
New function
check_required()to check that an argument is
supplied. It produces a more friendly error message thanforce()
(#1118). -
check_dots_empty(),check_dots_unused(), and
check_dots_unnamed()have been moved from ellipsis to rlang. The
ellipsis package is deprecated and will eventually be archived.We have added
check_dots_empty0(). It has a different UI but is
almost as efficient as checking formissing(...). Use this in very
low level functions where a couple microseconds make a difference. -
The
arg_nmargument ofarg_match0()must now be a string or
symbol. -
arg_match()now mentions the supplied argument (#1113). -
is_installed()andcheck_installed()gain aversionargument (#1165). -
check_installed()now consults the
rlib_restart_package_not_foundglobal option to determine whether
to prompt users to install packages. This also disables the restart
mechanism (see below). -
check_installed()now signals errors of class
rlib_error_package_not_foundwith a
rlib_restart_package_not_foundrestart. This allows calling
handlers to install the required packages and restart the check
(#1150). -
is_installed()andcheck_installed()now support
DESCRIPTION-style version requirements like"rlang (>= 1.0)".
They also gainversionandcomparearguments to supply requirements
programmatically. -
check_installed()gains anactionargument that is called when
the user chooses to install and update missing and outdated packages. -
New
check_exclusive()function to check that only one argument of
a set is supplied (#1261).
R APIs
-
on_load()andrun_on_load()lets you run.onLoad()expressions
from any file of your package.on_package_load()runs expressions
when another package is loaded. (#1284) -
The new predicate
is_call_simple()indicates whether a call has a
name and/or a namespace. It provides two invariants:-
If
is_call_simple(x)isTRUE,call_name()always returns a
string. -
If
is_call_simple(x, ns = TRUE)isTRUE,call_ns()always
returns a string.
-
-
call_name()andcall_ns()now returnNULLwith calls of the
formfoo::bar(#670). -
New
current_call(),caller_call(), andframe_call()
accessors. Newframe_fn()accessor. -
env_has()and the corresponding C-level function no longer force
active bindings (#1292). -
New
names2<-replacement function that never adds missing values
when names don't have names (#1301). -
zap_srcref()now preserves attributes of closures. -
Objects headers (as printed by
last_error(),env_print(), ...)
are now formatted using theclsclass of the cli package. -
as_function()gainsargandcallarguments to provide
contextual information about erroring inputs. -
is_expression()now returnsFALSEfor manually constructed
expressions that cannot be created by the R parser. -
New C callable
rlang_env_unbind(). This is a wrapper around
R_removeVarFromFrame()on R >= 4.0.0. On older R this wraps the R
functionbase::rm(). Unlikerm(), this function does not warn
(nor throw) when a binding does not exist. -
friendly_type_of()now supports missing arguments. -
env_clone()now properly clones active bindings and avoids forcing
promises (#1228). On R < 4.0, promises are still forced. -
Fixed an
s3_register()issue when the registering package is a
dependency of the package that exports the generic (#1225). -
Added
compat-vctrs.Rfile for robust manipulation of data frames
in zero-deps packages. -
Added
compat-cli.Rfile to format message elements consistently
with cli in zero-deps packages. -
compat-purrr.Rnow longer includespluck*helpers; these used a defintion
of pluck that predated purrr (#1159).*_cpl()has also been removed.
Themap*wrappers now callas_function()so that you can pass short
anonymous functions that use~(#1157). -
exprs_auto_name()gains arepair_autoargument to make automatic
names unique (#1116). -
The
.namedargument ofdots_list()can now be set toNULLto
give the result default names. With this option, fully unnamed
inputs produce a fully unnamed result withNULLnames instead of a
character vector of minimal""names (#390). -
is_named2()is a variant ofis_named()that always returns
TRUEfor empty vectors (#191). It tests for the property that each
element of a vector is named rather than the presence of anames
attribute. -
New
rlib_bytesclass imported from the bench package (#1117).
It prints and parses human-friendly sizes. -
The
envargument ofas_function()now defaults to the global
environment. Its previous default was the caller ofas_function(),
which was rarely the correct environment to look in. Since it's hard
to remember to pass the user environment and it's sometimes tricky
to keep track of it, it's best to consider string lookup as a
convenience for end users, not for developers (#1170). -
s3_register()no longer fails when generic does not exist. This
prevents failures when users don't have all the last versions of
packages (#1112). -
Formulas are now deparsed according to the tidyverse style guide
(~symbolwithout space and~ expression()with a space). -
New
hash_file(), complementinghash(), to generate 128-bit hashes for
the data within a file without loading it into R (#1134). -
New
env_cache()function to retrieve a value or create it with a
default if it doesn't exist yet (#1081). -
env_get()andenv_get_list()gain alastargument. Lookup
stops in that environment. This can be useful in conjunction with
base::topenv(). -
New
call_match()function. It is likematch.call()but also
supports matching missing arguments to their defaults in the function
definition (#875).call_standardise()is deprecated in favour ofcall_match(). -
expr_deparse()now properly escapes\characters in symbols,
argument names, and vector names (#1160). -
friendly_type_of()(fromcompat-friendly-type.R) now supports
matrices and arrays (#141). -
Updated
env_print()to useformat_error_bullets()and consistent
tidyverse style (#1154). -
set_names()now recycles names of size 1 to the size of the input,
following the tidyverse recycling rules. -
is_bare_formula()now handles thescopedargument
consistently. The default has been changed toTRUEfor
compatibility with the historical default behaviour (#1115). -
The "definition" API (
dots_definitions()etc.) has been archived. -
New
is_complex()predicates to complete the family (#1127). -
The C function
r_obj_address()now properly prefixes addresses
with the hexadecimal prefix0xon Windows (#1135). -
obj_address()is now exported. -
%<~%now actually works. -
XXH3_64bits()from the XXHash library is now exposed as C callable
under the namerlang_xxh3_64bits().