env_browse()
and env_is_browsed()
are now defunct as they require an API
that is no longer available to packages (#1727).
env_unlock()
is now defunct because recent versions of R no long
make it possible to unlock an environment (#1705). Make sure to use an
up-to-date version of pkgload (>= 1.4.0) following this change.
is_dictionaryish()
now will return TRUE for NULL (@ilovemane, #1712).
Added missing C level r_dyn_raw_push_back()
and r_dyn_chr_push_back()
utilities (#1699).
last_trace()
hyperlinks now use the modern x-r-run
format (#1678).
Fix for CRAN checks.
%||%
is now reexported from base on newer R versions. This avoids
conflict messages when attaching or importing rlang.
Fixed an off-by-one typo in the traceback source column location (#1633).
abort()
now respects the base R global option,
options(show.error.messages = FALSE)
(#1630).
obj_type_friendly()
now only displays the first class of S3 objects (#1622).
expr_label()
now has back-compatility with respect to changes made by R version 4.4 and is.atomic(NULL)
(#1655)
Performance improvement in .rlang_cli_compat()
(#1657).
englue()
now allows omitting {{
. This is to make it easier to
embed in external functions that need to support either {
and {{
(#1601).
Fix for CRAN checks.
stop_input_type()
now handles I()
input literally in arg
(#1607, @simonpcouch).
parse_expr()
and parse_exprs()
are now faster when
getOption("keep.source")
is TRUE
(#1603).
dots_splice()
is deprecated. This function was previously in
the questioning lifecycle stage as we were moving towards the
explicit !!!
splicing style.
flatten()
, squash()
, and their variants are deprecated in favour
of purrr::list_flatten()
and purrr::list_c()
.
child_env()
is deprecated in favour of env()
which has supported
creating child environments for several years now.
last_error()
and options(rlang_backtrace_on_error = "full")
now
print the full backtrace tree by default (except for some hidden
frames). The simplified backtraces tended to hide important context
too often. Now we show intervening frames in a lighter colour so
that they don't distract from the important parts of the backtraces
but are still easily inspectable.
global_entrace()
, last_warnings()
, and last_messages()
now
support knitr documents.
New rlang_backtrace_on_warning_report
global option. This is
useful in conjunction with global_entrace()
to get backtraces on
warnings inside RMarkdown documents.
global_entrace()
and entrace()
now stop entracing warnings and
messages after 20 times. This is to avoid a large overhead when 100s
or 1000s of warnings are signalled in a loop (#1473).
abort()
, warn()
, and inform()
gain an .inherit
parameter.
This controls whether parent
is inherited. If FALSE
,
cnd_inherits()
and try_fetch()
do not match chained conditions
across parents.
It's normally TRUE
by default, but if a warning is chained to an
error or a message is chained to a warning or error (downgraded
chaining), .inherit
defaults to FALSE
(#1573).
try_fetch()
now looks up condition classes across chained errors
(#1534). This makes try_fetch()
insensitive to changes of
implementation or context of evaluation that cause a classed error
to suddenly get chained to a contextual error.
englue()
gained env
, error_arg
, and error_call
arguments to
support being wrapped in another function (#1565).
The data-masking documentation for arguments has been imported from dplyr. You can link to it by starting an argument documentation with this button:
<[`data-masking`][rlang::args_data_masking]>
enquos()
and friends gain a .ignore_null
argument (#1450).
New env_is_user_facing()
function to determine if an evaluation
frame corresponds to a direct usage by the end user (from the global
environment or a package being tested) or indirect usage by a third
party function. The return value can be overridden by setting the
"rlang_user_facing"
global option.
New check_data_frame()
and check_logical()
functions in
standalone-types-check.R
(#1587, @mgirlich).
Added allow_infinite
argument to check_number_whole()
(#1588, @mgirlich).
The lifecycle standalone file has been updated to match the modern lifecycle tools.
parse_expr()
now supports vectors of lines (#1540).
Quosures can now be consistently concatenated to lists of quosures (#1446).
Fixed a memory issue that caused excessive duplication in list2()
and friends (#1491).
Embraced empty arguments are now properly detected and trimmed by
quos()
(#1421).
Fixed an edge case that caused enquos(.named = NULL)
to return a
named list (#1505).
expr_deparse()
now deparses the embrace operator {{
on a single
line (#1511).
zap_srcref()
has been rewritten in C for efficiency (#1513).
zap_srcref()
now supports expression vectors.
The non-error path of check_dots_unnamed()
has been rewritten in C
for efficiency (#1528).
Improved error messages in englue()
(#1531) and in glue strings in
the LHS of :=
(#1526).
englue()
now requires size 1 outputs (#1492). This prevents
surprising errors or inconsistencies when an interpolated input of
size != 1 makes its way into the glue string.
arg_match()
now throws correct error when supplied a missing value
or an empty vector (#1519).
is_integerish()
now handles negative doubles more consistently
with positive ones (@sorhawell, #1530).
New check_logical()
in standalone-types-check.R
(#1560).
quo_squash()
now squashes quosures in function position (#1509).
is_expression()
now recognises quoted functions (#1499).
It now also recognises non-parsable attributes (#1475).
obj_address()
now supports the missing argument (#1521).
Fixed a check_installed()
issue with packages removed during the
current R session (#1561).
new_data_mask()
is now slightly faster due to a smaller initial mask size
and usage of the C level function R_NewEnv()
on R >=4.1.0 (#1553).
The C level r_dyn_*_push_back()
utilities are now faster (#1542).
The C level r_lgl_sum()
and r_lgl_which()
helpers are now faster
(#1577, with contributions from @mgirlich).
rlang is now compliant with -Wstrict-prototypes
as requested by CRAN
(#1508).
as_closure(seq.int)
now works (#1468).
rlang no longer stores errors and backtraces in a org:r-lib
environment on the search path.
The low-level function error_call()
is now exported (#1474).
Fixed an issue that caused a failure about a missing is_character
function when rlang is installed alongside an old version of vctrs (#1482).
Fixed an issue that caused multiline calls in backtraces.
The C API function r_lgl_which()
now propagates the names of the input
(#1471).
The pkg_version_info()
function now allows ==
for package
version comparison (#1469, @kryekuzhinieri).
Fixed backtrace display with calls containing long lists of arguments (#1456).
New r_obj_type_friendly()
function in the C library (#1463). It
interfaces with obj_type_friendly()
from compat-obj-type.R
via a
C callable.
is_installed()
no longer throws an error with irregular package
names.
is_installed()
and check_installed()
now properly detect that
the base package is installed on older versions of R (#1434).
Child errors may now have empty messages to enable this pattern:
Error in `my_function()`:
Caused by error in `their_function()`:
! Message.
The rlib_bytes
class now uses prettyunits to format bytes. The
bytes are now represented with decimal prefixes instead of binary
prefixes.
Supplying a frame environment to the call
argument of abort()
now causes the corresponding function call in the backtrace to be
highlighted.
In addition, if you store the argument name of a failing input in
the arg
error field, the argument is also highlighted in the
backtrace.
Instead of:
cli::cli_abort("{.arg {arg}} must be a foobar.", call = call)
You can now write this to benefit from arg highlighting:
cli::cli_abort("{.arg {arg}} must be a foobar.", arg = arg, call = call)
abort(message = )
can now be a function. In this case, it is
stored in the header
field and acts as a cnd_header()
method
invoked when the message is displayed.
New obj_type_oo()
function in compat-obj-type.R
(#1426).
friendly_type_of()
from compat-obj-type.R
(formerly
compat-friendly-type.R
) is now obj_type_friendly()
.
options(backtrace_on_error = "collapse")
and print(trace, simplify = "collapse")
are deprecated. They fall back to "none"
with a warning.
call_match()
now better handles ...
when dots_expand = FALSE
.
list2(!!!x)
is now faster when x
is a list. It is now returned
as is instead of being duplicated into a new list.
abort()
gains a .trace_bottom
argument to disambiguate from
other .frame
. This allows cli::cli_abort()
to wrap abort()
in
such a way that .internal
mentions the correct package to report
the error in (#1386).
The transpose()
compat is now more consistent with purrr when
inner names are not congruent (#1346).
New reset_warning_verbosity()
and reset_message_verbosity()
functions. These reset the verbosity of messages signalled with
warn()
and inform()
with the .frequency
argument. This is
useful for testing verbosity in your package (#1414).
check_dots_empty()
now allows trailing missing arguments (#1390).
Calls to local functions that are not accessible through ::
or
:::
are now marked with (local)
in backtraces (#1399).
Error messages now mention indexed calls like foo$bar()
.
New env_coalesce()
function to copy bindings from one environment
to another. Unlike approaches based on looping with [[<-
,
env_coalesce()
preserves active and lazy bindings.
Chaining errors at top-level (directly in the console instead of in a function) no longer fails (#1405).
Warning style is propagated across parent errors in chained error messages (#1387).
check_installed()
now works within catch-all tryCatch(error = )
expressions (#1402, tidyverse/ggplot2#4845).
arg_match()
and arg_match0()
now mention the correct call in
case of type error (#1388).
abort()
and inform()
now print messages to stdout
in RStudio
panes (#1393).
is_installed()
now detects unsealed namespaces (#1378). This fixes
inconsistent behaviour when run within user onLoad hooks.
Source references in backtraces and last_error()
/last_trace()
instructions
are now clickable in IDEs that support links (#1396).
compat-cli.R
now supports style_hyperlink()
.
abort(.homonyms = "error")
now throws the expected error (#1394).
env_binding_are_active()
no longer accidentally triggers active bindings
(#1376).
Fixed bug in quo_squash()
with nested quosures containing the
missing argument.
Backtraces of parent errors are now reused on rethrow. This avoids capturing the same backtrace twice and solves consistency problems by making sure both errors in a chain have the same backtrace.
Fixed backtrace oversimplification when cnd
is a base error in
abort(parent = cnd)
.
Internal errors thrown with abort(.internal = TRUE)
now mention
the name of the package the error should be reported to.
Backtraces are now separated from error messages with a ---
ruler
line (#1368).
The internal bullet formatting routine now ignores unknown names (#1364). This makes it consistent with the cli package, increases resilience against hard-to-detect errors, and increases forward compatibility.
abort()
and friends no longer calls non-existent functions
(e.g. cli::format_error()
or cli::format_warning
) when the
installed version of cli is too old (#1367, tidyverse/dplyr#6189).
Fixed an OOB subsetting error in abort()
.
New rlang_call_format_srcrefs
global option (#1349). Similar to
rlang_trace_format_srcrefs
, this option allows turning off the
display of srcrefs in error calls. This can be useful for
reproducibility but note that srcrefs are already disabled
within testthat by default.
abort(parent = NA)
is now supported to indicate an unchained
rethrow. This helps abort()
detect the condition handling context
to create simpler backtraces where this context is hidden by
default.
When parent
is supplied, abort()
now loops over callers to
detect the condition handler frame. This makes it easier to wrap or
extract condition handlers in functions without supplying .frame
.
When parent
is supplied and call
points to the condition setup
frame (e.g. withCallingHandlers()
or try_fetch()
), call
is
replaced with the caller of that setup frame. This provides a more
helpful default call.
is_call()
is now implemented in C for performance.
Fixed performance regression in trace_back()
.
Fixed a partial matching issue with header
, body
, and footer
condition fields.
eval_tidy()
calls are no longer mentioned in error messages.
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 the parent
argument. 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 a call
argument that
you can set to caller_env()
or parent.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 like tryCatch()
with a few
important differences.
Compared to tryCatch()
, try_fetch()
preserves the call
stack. This allows full backtrace capture and allows recover()
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.
The .data
object exported by rlang now fails when subsetted
instead of returning NULL
. This new error helps you detect when
.data
is used in the wrong context.
We've noticed several packages failing after this change because
they were using .data
outside of a data-masking context. For
instance the by
argument of dplyr::join()
is not data-masked.
Previously dplyr::join(by = .data$foo)
would silently be
interpreted as dplyr::join(by = NULL)
. This is now an error.
Another issue is using .data
inside ggplot2::labs(...)
. This is
not allowed since labs()
isn't data-masked.
call_name()
now returns NULL
instead of "::"
for calls of the
form foo::bar
.
We've noticed some packages do not check for NULL
results from
call_name()
. Note that many complex calls such as foo()()
,
foo$bar()
don't have a "name" and cause a NULL
result. This is
why you should always check for NULL
results when using
call_name()
.
We've added the function is_call_simple()
to make it easier to
work safely with call_name()
. The invariant is that call_name()
always returns a string when is_call_simple()
returns TRUE
.
Conversely it always returns NULL
when is_call_simple()
retuns
FALSE
.
is_expression()
now returns FALSE
for manually constructed
expressions that can't be created by the parser. It used to return
TRUE
for 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 to as_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()
, and friendly_type()
are deprecated.
The action
argument of check_dots_used()
, check_dots_unnamed()
,
and check_dots_empty()
is deprecated in favour of the new error
argument which takes an error handler.
Many functions deprecated in rlang 0.2.0 and 0.3.0 have been removed from the package.
New englue()
operator to allow string-embracing outside of dynamic
dots (#1172).
New data_sym()
and data_syms()
functions to create calls of the
form .data$foo
.
.data
now 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 like tibble()
, 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_empty
argument of enexprs()
and enquos()
no longer
treats named arguments supplied through ...
as empty, consistently
with exprs()
and quos()
(#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).
try_fetch()
is a flexible alternative to both tryCatch()
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_error
support for all conditions.
New global_handle()
function to install a default configuration of
error handlers. This currently calls global_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 by abort()
:
The call
field of error messages is now displayed, as is the
default in base::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 (code
formatting
by the cli package if available).
The source location is displayed (as in base::stop()
) if call
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 parent
argument 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:
inform()
and warn()
messages can now be silenced with the global
options rlib_message_verbosity
and rlib_warning_verbosity
.
abort()
now outputs error messages to stdout
in interactive
sessions, following the same approach as inform()
.
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:
"v"
as green ticks (@rossellhayes)" "
as indented line breaks"*"
as normal bullets"!"
as warning bulletsFor convenience, a fully unnamed vector is interpreted as a vector
of "*"
bullets.
abort()
gains a .internal
argument. When set to TRUE
, a footer
bullet is added to message
to let the user know that the error is
internal and that they should report it to the package authors.
abort()
, warn()
, and inform()
gain a body
argument 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()
.
header
and footer
methods can now be stored as closures in
condition fields of the same name.
cnd_message()
gains a prefix
argument to print the message with
a full prefix, including call
field if present and parent messages
if the condition is chained.
cnd_message()
gains an inherit
argument to control whether to
print the messages of parent errors.
Condition constructors now check for duplicate field names (#1268).
cnd_footer()
now returns the footer
field by default, if any.
warn()
and inform()
now signal conditions of classes
"rlang_warning"
and "rlang_message"
respectively.
The body
field 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.error
binding of the "org:r-lib"
environment. This is consistent with how the processx package
records error conditions. Printing the .Last.error
object is now
equivalent to running last_error()
.
Added is_error()
, is_warning()
, and is_message()
predicates (#1220).
interrupt()
no longer fails when interrupts are suspended (#1224).
warn()
now temporarily sets the warning.length
global 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).
entrace()
and global_entrace()
now log warnings and messages
with backtraces attached. Run last_warnings()
or last_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 for expected errors in dynamic reports
(chunks where error = TRUE
in knitted documents and RStudio
notebooks) is now controlled by the
rlang_backtrace_on_error_report
option. By default, this is set to
"none"
.
The display of backtraces for unexpected errors (in chunks where
error
is unset or set to FALSE
) is still controlled by
rlang_backtrace_on_error
.
The last_error()
reminder is no longer displayed in RStudio
notebooks.
A knitr::sew()
method is registered for rlang_error
. This makes
it possible to consult last_error()
(the call must occur in a
different chunk than the error) and to set
rlang_backtrace_on_error_report
global options in knitr to display
a backtrace for expected errors.
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_env
global option for trace_back()
now
detects when backtraces are created within knitr. If the option is
not set, its default value becomes knitr::knit_global()
when knitr
is in progress (as determined from knitr.in.progress
global
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).
arg_match()
gains a multiple
argument 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 than force()
(#1118).
check_dots_empty()
, check_dots_used()
, 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 for missing(...)
. Use this in very
low level functions where a couple microseconds make a difference.
The arg_nm
argument of arg_match0()
must now be a string or
symbol.
arg_match()
now mentions the supplied argument (#1113).
is_installed()
and check_installed()
gain a version
argument (#1165).
check_installed()
now consults the
rlib_restart_package_not_found
global 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_found
with a
rlib_restart_package_not_found
restart. This allows calling
handlers to install the required packages and restart the check
(#1150).
is_installed()
and check_installed()
now support
DESCRIPTION-style version requirements like "rlang (>= 1.0)"
.
They also gain version
and compare
arguments to supply requirements
programmatically.
check_installed()
gains an action
argument 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).
on_load()
and run_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)
is TRUE
, call_name()
always returns a
string.
If is_call_simple(x, ns = TRUE)
is TRUE
, call_ns()
always
returns a string.
call_name()
and call_ns()
now return NULL
with calls of the
form foo::bar
(#670).
New current_call()
, caller_call()
, and frame_call()
accessors. New frame_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 the cls
class of the cli package.
as_function()
gains arg
and call
arguments to provide
contextual information about erroring inputs.
is_expression()
now returns FALSE
for 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
function base::rm()
. Unlike rm()
, 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.R
file for robust manipulation of data frames
in zero-deps packages.
Added compat-cli.R
file to format message elements consistently
with cli in zero-deps packages.
compat-purrr.R
now longer includes pluck*
helpers; these used a defintion
of pluck that predated purrr (#1159). *_cpl()
has also been removed.
The map*
wrappers now call as_function()
so that you can pass short
anonymous functions that use ~
(#1157).
exprs_auto_name()
gains a repair_auto
argument to make automatic
names unique (#1116).
The .named
argument of dots_list()
can now be set to NULL
to
give the result default names. With this option, fully unnamed
inputs produce a fully unnamed result with NULL
names instead of a
character vector of minimal ""
names (#390).
is_named2()
is a variant of is_named()
that always returns
TRUE
for empty vectors (#191). It tests for the property that each
element of a vector is named rather than the presence of a names
attribute.
New rlib_bytes
class imported from the bench package (#1117).
It prints and parses human-friendly sizes.
The env
argument of as_function()
now defaults to the global
environment. Its previous default was the caller of as_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
(~symbol
without space and ~ expression()
with a space).
New hash_file()
, complementing hash()
, 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()
and env_get_list()
gain a last
argument. Lookup
stops in that environment. This can be useful in conjunction with
base::topenv()
.
New call_match()
function. It is like match.call()
but also
supports matching missing arguments to their defaults in the function
definition (#875).
call_standardise()
is deprecated in favour of call_match()
.
expr_deparse()
now properly escapes \
characters in symbols,
argument names, and vector names (#1160).
friendly_type_of()
(from compat-friendly-type.R
) now supports
matrices and arrays (#141).
Updated env_print()
to use format_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 the scoped
argument
consistently. The default has been changed to TRUE
for
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 prefix 0x
on Windows (#1135).
obj_address()
is now exported.
%<~%
now actually works.
XXH3_64bits()
from the XXHash library is now exposed as C callable
under the name rlang_xxh3_64bits()
.
Fix for CRAN checks.
Fixed a gcc11 warning related to hash()
(#1088).
New hash()
function to generate 128-bit hashes for arbitrary R objects
using the xxHash library. The implementation is modeled after
xxhashlite, created
by @coolbutuseless.
New check_installed()
function. Unlike is_installed()
, it asks
the user whether to install missing packages. If the user accepts,
the packages are installed with pak::pkg_install()
if available,
or utils::install.packages()
otherwise. If the session is non
interactive or if the user chooses not to install the packages, the
current evaluation is aborted (#1075).
rlang is now licensed as MIT (#1063).
Fixed an issue causing extra empty lines in inform()
messages with
.frequency
(#1076, @schloerke).
expr_deparse()
now correctly wraps code using ::
and :::
(#1072, @krlmlr).
inject()
evaluates its argument with !!
, !!!
, and {{
support.
New enquo0()
and enquos0()
operators for defusing function
arguments without automatic injection (unquotation).
format_error_bullets()
is no longer experimental. The message
arguments of abort()
, warn()
, and inform()
are automatically
passed to that function to make it easy to create messages with
regular, info, and error bullets. See ?format_error_bullets
for
more information.
New zap_srcref()
function to recursively remove source references
from functions and calls.
A new compat file for the zeallot operator %<-%
is now available
in the rlang repository.
New %<~%
operator to define a variable lazily.
New env_browse()
and env_is_browsed()
functions. env_browse()
is equivalent to evaluating browser()
within an environment. It
sets the environment to be persistently browsable (or unsets it if
value = FALSE
is supplied).
Functions created from quosures with as_function()
now print in a
more user friendly way.
New rlang_print_backtrace
C callable for debugging from C
interpreters (#1059).
The .data
pronoun no longer skips functions (#1061). This solves a
dplyr issue involving rowwise data frames and list-columns of
functions (tidyverse/dplyr#5608).
as_data_mask()
now intialises environments of the correct size to
improve efficiency (#1048).
eval_bare()
, eval_tidy()
(#961), and with_handlers()
(#518)
now propagate visibility.
cnd_signal()
now ignores NULL
inputs.
Fixed bug that prevented splicing a named empty vector with the
!!!
operator (#1045).
The exit status of is now preserved in non-interactive sessions when
entrace()
is used as an options(error = )
handler (#1052,
rstudio/bookdown#920).
next
and break
are now properly deparsed as nullary operators.
Backtraces now include native stacks (e.g. from C code) when the
winch package is installed and
rlang_trace_use_winch
is set to TRUE
(@krlmlr).
Compatibility with upcoming testthat 3 and magrittr 2 releases.
get_env()
now returns the proper environment with primitive
functions, i.e. the base namespace rather than the base environment
(r-lib/downlit#32).
entrace()
no longer handles non-rlang errors that carry a
backtrace. This improves compatibility with packages like callr.
Backtraces of unhandled errors are now displayed without truncation in non-interactive sessions (#856).
is_interactive()
no longer consults "rstudio.notebook.executing"
option (#1031).
cnd_muffle()
now returns FALSE
instead of failing if the
condition is not mufflable (#1022).
warn()
and inform()
gain a .frequency
argument to control how
frequently the warning or message should be displayed.
New raw_deparse_str()
function for converting a raw vector into a
string of hexadecimal characters (@krlmlr, #978).
The backtraces of chained errors are no longer decomposed by error context. Instead, the error messages are displayed as a tree to reflect the error ancestry, and the deepest backtrace in the ancestry is displayed.
This change simplifies the display (#851) and makes it possible to
rethow errors from a calling handler rather than an exiting handler,
which we now think is more appropriate because it allows users to
recover()
into the error.
env_bind()
, env_bind_active()
, env_bind_lazy()
, env_get()
,
and env_get_list()
have been rewritten in C.
env_poke()
now supports zap()
sentinels for removing bindings
(#1012) and has better support for characters that are not
representable in the local encoding.
env_poke()
has been rewritten in C for performance.
The unicode translation warnings that appeared on Windows with R 4.0 are now fixed.
env_unbind(inherit = TRUE)
now only removes a binding from the
first parent environment that has a binding. It used to remove the
bindings from the whole ancestry. The new behaviour doesn't
guarantee that a scope doesn't have a binding but it is safer.
env_has()
is now rewritten in C for performance.
dots_list()
gains a .named
argument for auto-naming dots (#957).
It is now possible to subset the .data
pronoun with quosured
symbols or strings (#807).
Expressions like quote(list("a b" = 1))
are now properly deparsed
by expr_deparse()
(#950).
parse_exprs()
now preserves names (#808). When a single string
produces multiple expressions, the names may be useful to figure out
what input produced which expression.
parse_exprs()
now supports empty expressions (#954).
list2(!!!x)
no longer evaluates x
multiple times (#981).
is_installed()
now properly handles a pkg
argument of length > 1.
Before this it silently tested the first element of pkg
only
and thus always returned TRUE
if the first package was installed
regardless of the actual length of pkg
. (#991, @salim-b)
arg_match0()
is a faster version of arg_match()
for use when performance
is at a premium (#997, @krlmlr).
!!!
now uses a combination of length()
, names()
, and [[
to splice
S3 and S4 objects. This produces more consistent behaviour than as.list()
on a wider variety of vector classes (#945, tidyverse/dplyr#4931).set_names()
, is_formula()
, and names2()
are now implemented in
C for efficiency.
The .data
pronoun now accepts symbol subscripts (#836).
Quosure lists now explicitly inherit from "list"
. This makes them
compatible with the vctrs package (#928).
All rlang options are now documented in a centralised place, see
?rlang::faq-options
(#899, @smingerson).
Fixed crash when env_bindings_are_lazy()
gets improper arguments (#923).
arg_match()
now detects and suggests possible typos in provided
arguments (@jonkeane, #798).
arg_match()
now gives an error if argument is of length greater
than 1 and doesn't exactly match the values input, similar to base
match.arg
(#914, @AliciaSchep)
You can now use glue syntax to unquote on the LHS of :=
. This
syntax is automatically available in all functions taking dots with
list2()
and enquos()
, and thus most of the tidyverse. Note that
if you use the glue syntax in an R package, you need to import glue.
A single pair of braces triggers normal glue interpolation:
df <- data.frame(x = 1:3)
suffix <- "foo"
df %>% dplyr::mutate("var_{suffix}" := x * 2)
#> x var_foo
#> 1 1 2
#> 2 2 4
#> 3 3 6
Using a pair of double braces is for labelling a function argument.
Technically, this is shortcut for "{as_label(enquo(arg))}"
. The
syntax is similar to the curly-curly syntax for interpolating
function arguments:
my_wrapper <- function(data, var, suffix = "foo") {
data %>% dplyr::mutate("{{ var }}_{suffix}" := {{ var }} * 2)
}
df %>% my_wrapper(x)
#> x x_foo
#> 1 1 2
#> 2 2 4
#> 3 3 6
df %>% my_wrapper(sqrt(x))
#> x sqrt(x)_foo
#> 1 1 2.000000
#> 2 2 2.828427
#> 3 3 3.464102
Fixed a bug in magrittr backtraces that caused duplicate calls to appear in the trace.
Fixed a bug in magrittr backtraces that caused wrong call indices.
Empty backtraces are no longer shown when rlang_backtrace_on_error
is set.
The tidy eval .env
pronoun is now exported for documentation
purposes.
warn()
and abort()
now check that either class
or message
was supplied. inform()
allows sending empty message as it is
occasionally useful for building user output incrementally.
flatten()
fails with a proper error when input can't be flattened (#868, #885).
inform()
now consistently appends a final newline to the message
(#880).
cnd_body.default()
is now properly registered.
cnd_signal()
now uses the same approach as abort()
to save
unhandled errors to last_error()
.
Parsable constants like NaN
and NA_integer_
are now deparsed by
expr_deparse()
in their parsable form (#890).
Infix operators now stick to their LHS when deparsed by
expr_deparse()
(#890).
New cnd_header()
, cnd_body()
and cnd_footer()
generics. These
are automatically called by conditionMessage.rlang_error()
, the
default method for all rlang errors.
Concretely, this is a way of breaking up lazy generation of error
messages with conditionMessage()
into three independent
parts. This provides a lot of flexibility for hierarchies of error
classes, for instance you could inherit the body of an error message
from a parent class while overriding the header and footer.
The reminder to call last_error()
is now less confusing thanks to
a suggestion by @markhwhiteii.
The functions prefixed in scoped_
have been renamed to use the
more conventional local_
prefix. For instance, scoped_bindings()
is now local_bindings()
. The scoped_
functions will be
deprecated in the next significant version of rlang (0.5.0).
The .subclass
argument of abort()
, warn()
and inform()
has
been renamed to class
. This is for consistency with our
conventions for class constructors documented in
https://adv-r.hadley.nz/s3.html#s3-subclassing.
inform()
now prints messages to the standard output by default in
interactive sessions. This makes them appear more like normal output
in IDEs such as RStudio. In non-interactive sessions, messages are
still printed to standard error to make it easy to redirect messages
when running R scripts (#852).
Fixed an error in trace_back()
when the call stack contains a
quosured symbol.
Backtrace is now displayed in full when an error occurs in non-interactive sessions. Previously the backtraces of parent errors were left out.
New experimental framework for creating bulleted error messages. See
?cnd_message
for the motivation and an overwiew of the tools we
have created to support this approach. In particular, abort()
now
takes character vectors to assemble a bullet list. Elements named
x
are prefixed with a red cross, elements named i
are prefixed
with a blue info symbol, and unnamed elements are prefixed with a
bullet.
Capture of backtrace in the context of rethrowing an error from an
exiting handler has been improved. The tryCatch()
context no
longer leaks in the high-level backtrace.
Printing an error no longer recommends calling last_trace()
,
unless called from last_error()
.
env_clone()
no longer recreates active bindings and is now just an
alias for env2list(as.list(env))
. Unlike as.list()
which returns
the active binding function on R < 4.0, the value of active bindings
is consistently used in all versions.
The display of rlang errors derived from parent errors has been
improved. The simplified backtrace (as printed by
rlang::last_error()
) no longer includes the parent errors. On the
other hand, the full backtrace (as printed by rlang::last_trace()
)
now includes the backtraces of the parent errors.
cnd_signal()
has improved support for rlang errors created with
error_cnd()
. It now records a backtrace if there isn't one
already, and saves the error so it can be inspected with
rlang::last_error()
.
rlang errors are no longer formatted and saved through
conditionMessage()
. This makes it easier to use a
conditionMessage()
method in subclasses created with abort()
,
which is useful to delay expensive generation of error messages
until display time.
abort()
can now be called without error message. This is useful
when conditionMessage()
is used to generate the message at
print-time.
Fixed an infinite loop in eval_tidy()
. It occurred when evaluating
a quosure that inherits from the mask itself.
env_bind()
's performance has been significantly improved by fixing a bug
that caused values to be repeatedly looked up by name.
cnd_muffle()
now checks that a restart exists before invoking
it. The restart might not exist if the condition is signalled with a
different function (such as stop(warning_cnd)
).
trace_length()
returns the number of frames in a backtrace.
Added internal utility cnd_entrace()
to add a backtrace to a
condition.
rlang::last_error()
backtraces are no longer displayed in red.
x %|% y
now also works when y
is of same length as x
(@rcannood, #806).
Empty named lists are now deparsed more explicitly as
"<named list>"
.
Fixed chr()
bug causing it to return invisibly.
The main change of this release is the new tidy evaluation operator
{{
. This operator abstracts the quote-and-unquote idiom into a
single interpolation step:
my_wrapper <- function(data, var, by) {
data %>%
group_by({{ by }}) %>%
summarise(average = mean({{ var }}, na.rm = TRUE))
}
{{ var }}
is a shortcut for !!enquo(var)
that should be easier on
the eyes, and easier to learn and teach.
Note that for multiple inputs, the existing documentation doesn't stress enough that you can just pass dots straight to other tidy eval functions. There is no need for quote-and-unquote unless you need to modify the inputs or their names in some way:
my_wrapper <- function(data, var, ...) {
data %>%
group_by(...) %>%
summarise(average = mean({{ var }}, na.rm = TRUE))
}
.env
pronounAnother improvement to tidy evaluation should make it easier to use
the .env
pronoun. Starting from this release, subsetting an object
from the .env
pronoun now evaluates the corresponding symbol. This
makes .env
more robust, in particular in magrittr pipelines. The
following example would previously fail:
foo <- 10
mtcars %>% mutate(cyl = cyl * .env$foo)
This way, using the .env
pronoun is now equivalent to unquoting a
constant objects, but with an easier syntax:
mtcars %>% mutate(cyl = cyl * !!foo)
Note that following this change, and despite its name, .env
is no
longer referring to a bare environment. Instead, it is a special
shortcut with its own rules. Similarly, the .data
pronoun is not
really a data frame.
New pairlist2()
function with splicing support. It preserves
missing arguments, which makes it useful for lists of formal
parameters for functions.
is_bool()
is a scalar type predicate that checks whether its input
is a single TRUE
or FALSE
. Like is_string()
, it returns
FALSE
when the input is missing. This is useful for type-checking
function arguments (#695).
is_string()
gains a string
argument. is_string(x, "foo")
is a
shortcut for is_character(x) && length(x) == 1 && identical(x, "foo")
.
Lists of quosures now have pillar methods for display in tibbles.
set_names()
now names unnamed input vectors before applying a
function. The following expressions are now equivalent:
letters %>% set_names() %>% set_names(toupper)
letters %>% set_names(toupper)
You can now pass a character vector as message argument for
abort()
, warn()
, inform()
, and signal()
. The vector is
collapsed to a single string with a "\n"
newline separating each
element of the input vector (#744).
maybe_missing()
gains a default
argument.
New functions for weak references: new_weakref()
, weakref_key()
,
weakref_value()
, and is_weakref()
(@wch, #787).
The performance of exec()
has been improved. It is now on the same
order of performance as do.call()
, though slightly slower.
call2()
now uses the new pairlist2()
function internally. This
considerably improves its performance. This also means it now
preserves empty arguments:
call2("fn", 1, , foo = )
#> fn(1, , foo = )
with_handlers()
now installs calling handlers first on the stack,
no matter their location in the argument list. This way they always
take precedence over exiting handlers, which ensures their side
effects (such as logging) take place (#718).
In rlang backtraces, the global::
prefix is now only added when
the function directly inherits from the global environment.
Functions inheriting indirectly no longer have a namespace
qualifier (#733).
options(error = rlang::entrace)
now has better support for errors
thrown from C (#779). It also saves structured errors in the error
field of rlang::last_error()
.
ns_env()
and ns_env_name()
(experimental functions) now support
functions and environments consisently. They also require an
argument from now on.
is_interactive()
is aware of the TESTTHAT
environment variable and
returns FALSE
when it is "true"
(@jennybc, #738).
fn_fmls()
and variants no longer coerce their input to a
closure. Instead, they throw an error.
Fixed an issue in knitr that caused backtraces to print even when error = TRUE
.
The return object from as_function()
now inherits from
"function"
(@richierocks, #735).
We commit to support 5 versions of R. As R 3.6 is about to be released, rlang now requires R 3.2 or greater. We're also continuing our efforts to streamline and narrow the rlang API.
modify()
and prepend()
(two experimental functions marked as in
the questioning stage since rlang 0.3.0) are now deprecated. Vector
functions are now out of scope for rlang. They might be revived in
the vctrs or funs packages.
exiting()
is soft-deprecated because with_handlers()
treats
handlers as exiting by default.
The vector constructors like lgl()
or new_logical()
are now in
the questioning stage. They are likely to be moved to the vctrs
package at some point. Same for the missing values shortcuts like
na_lgl
.
as_logical()
, as_integer()
, etc have been soft-deprecated in
favour of vctrs::vec_cast()
.
type_of()
, switch_type()
, coerce_type()
, and friends are
soft-deprecated.
The encoding and locale API was summarily archived. This API didn't bring any value and wasn't used on CRAN.
lang_type_of()
, switch_lang()
, and coerce_lang()
were
archived. These functions were not used on CRAN or internally.
Subsetting quosures with [
or [[
is soft-deprecated.
All functions that were soft-deprecated, deprecated, or defunct in previous releases have been bumped to the next lifecycle stage.
Fixed protection issue reported by rchk.
The experimental option rlang__backtrace_on_error
is no longer
experimental and has been renamed to rlang_backtrace_on_error
.
New "none" option for rlang_backtrace_on_error
.
Unary operators applied to quosures now give better error messages.
Fixed issue with backtraces of warnings promoted to error, and
entraced via withCallingHandlers()
. The issue didn't affect
entracing via top level options(error = rlang::entrace)
handling.
This patch release polishes the new backtrace feature introduced in
rlang 0.3.0 and solves bugs for the upcoming release of purrr
0.3.0. It also features as_label()
and as_name()
which are meant
to replace quo_name()
in the future. Finally, a bunch of deparsing
issues have been fixed.
New entrace()
condition handler. Add this to your RProfile to
enable rlang backtraces for all errors, including warnings promoted
to errors:
if (requireNamespace("rlang", quietly = TRUE)) {
options(error = rlang::entrace)
}
This handler also works as a calling handler:
with_handlers(
error = calling(entrace),
foo(bar)
)
However it's often more practical to use with_abort()
in that case:
with_abort(foo(bar))
with_abort()
gains a classes
argument to promote any kind of
condition to an rlang error.
New last_trace()
shortcut to print the backtrace stored in the
last_error()
.
Backtrace objects now print in full by default.
Calls in backtraces are now numbered according to their position in the call tree. The numbering is non-contiguous for simplified backtraces because of omitted call frames.
catch_cnd()
gains a classes
argument to specify which classes of
condition to catch. It returns NULL
if the expected condition
could not be caught (#696).
The new as_label()
and as_name()
functions should be used instead
of quo_name()
to transform objects and quoted expressions to a
string. We have noticed that tidy eval users often use quo_name()
to
extract names from quosured symbols. This is not a good use for that
function because the way quo_name()
creates a string is not a well
defined operation.
For this reason, we are replacing quo_name()
with two new functions
that have more clearly defined purposes, and hopefully better names
reflecting those purposes. Use as_label()
to transform any object to
a short human-readable description, and as_name()
to extract names
from (possibly quosured) symbols.
Create labels with as_label()
to:
Display an object in a concise way, for example to labellise axes in a graphical plot.
Give default names to columns in a data frame. In this case, labelling is the first step before name repair.
We expect as_label()
to gain additional parameters in the future,
for example to control the maximum width of a label. The way an object
is labelled is thus subject to change.
On the other hand, as_name()
transforms symbols back to a string in
a well defined manner. Unlike as_label()
, as_name()
guarantees the
roundtrip symbol -> string -> symbol.
In general, if you don't know for sure what kind of object you're
dealing with (a call, a symbol, an unquoted constant), use
as_label()
and make no assumption about the resulting string. If you
know you have a symbol and need the name of the object it refers to,
use as_name()
. For instance, use as_label()
with objects captured
with enquo()
and as_name()
with symbols captured with ensym()
.
Note that quo_name()
will only be soft-deprecated at the next major
version of rlang (0.4.0). At this point, it will start issuing
once-per-session warnings in scripts, but not in packages. It will
then be deprecated in yet another major version, at which point it
will issue once-per-session warnings in packages as well. You thus
have plenty of time to change your code.
New is_interactive()
function. It serves the same purpose as
base::interactive()
but also checks if knitr is in progress and
provides an escape hatch. Use with_interactive()
and
scoped_interactive()
to override the return value of
is_interactive()
. This is useful in unit tests or to manually turn
on interactive features in RMarkdown outputs
calling()
now boxes its argument.
New done()
function to box a value. Done boxes are sentinels to
indicate early termination of a loop or computation. For instance,
it will be used in the purrr package to allow users to shortcircuit
a reduction or accumulation.
new_box()
now accepts additional attributes passed to structure()
.
Fixed a quotation bug with binary operators of zero or one argument
such as `/`(1)
(#652). They are now deparsed and printed
properly as well.
New call_ns()
function to retrieve the namespace of a
call. Returns NULL
if the call is not namespaced.
Top-level S3 objects are now deparsed properly.
Empty {
blocks are now deparsed on the same line.
Fixed a deparsing issue with symbols containing non-ASCII characters (#691).
expr_print()
now handles [
and [[
operators correctly, and
deparses non-syntactic symbols with backticks.
call_modify()
now respects ordering of unnamed inputs. Before this
fix, it would move all unnamed inputs after named ones.
as_closure()
wrappers now call primitives with positional
arguments to avoid edge case issues of argument matching.
as_closure()
wrappers now dispatch properly on methods defined in
the global environment (tidyverse/purrr#459).
as_closure()
now supports both base-style (e1
and e2
) and
purrr-style (.x
and .y
) arguments with binary primitives.
exec()
takes .fn
as first argument instead of f
, for
consistency with other rlang functions.
Fixed infinite loop with quosures created inside a data mask.
Base errors set as parent
of rlang errors are now printed
correctly.
The rlang API is still maturing. In this section, you'll find hard breaking changes. See the life cycle section below for an exhaustive list of API changes.
quo_text()
now deparses non-syntactic symbols with backticks:
quo_text(sym("foo+"))
#> [1] "`foo+`"
This caused a number of issues in reverse dependencies as
quo_text()
tends to be used for converting symbols to strings.
quo_text()
and quo_name()
should not be used for this purpose
because they are general purpose deparsers. These functions should
generally only be used for printing outputs or creating default
labels. If you need to convert symbols to strings, please use
as_string()
rather than quo_text()
.
We have extended the documentation of ?quo_text
and ?quo_name
to
make these points clearer.
exprs()
no longer flattens quosures. exprs(!!!quos(x, y))
is now
equivalent to quos(x, y)
.
The sentinel for removing arguments in call_modify()
has been
changed from NULL
to zap()
. This breaking change is motivated
by the ambiguity of NULL
with valid argument values.
call_modify(call, arg = NULL) # Add `arg = NULL` to the call
call_modify(call, arg = zap()) # Remove the `arg` argument from the call
The %@%
operator now quotes its input and supports S4 objects.
This makes it directly equivalent to @
except that it extracts
attributes for non-S4 objects (#207).
Taking the env_parent()
of the empty environment is now an error.
The changes for this version are organised around three main themes: error reporting, tidy eval, and tidy dots.
abort()
now records backtraces automatically in the error object.
Errors thrown with abort()
invite users to call
rlang::last_error()
to see a backtrace and help identifying where
and why the error occurred. The backtraces created by rlang (you can
create one manually with trace_back()
) are printed in a simplified
form by default that removes implementation details from the
backtrace. To see the full backtrace, call
summary(rlang::last_error())
.
abort()
also gains a parent
argument. This is meant for
situations where you're calling a low level API (to download a file,
parse a JSON file, etc) and would like to intercept errors with
base::tryCatch()
or rlang::with_handlers()
and rethrow them with
a high-level message. Call abort()
with the intercepted error as
the parent
argument. When the user prints rlang::last_error()
,
the backtrace will be shown in two sections corresponding to the
high-level and low-level contexts.
In order to get segmented backtraces, the low-level error has to be
thrown with abort()
. When that's not the case, you can call the
low-level function within with_abort()
to automatically promote
all errors to rlang errors.
The tidy eval changes are mostly for developers of data masking
APIs. The main user-facing change is that .data[[
is now an
unquote operator so that var
in .data[[var]]
is never masked by
data frame columns and always picked from the environment. This
makes the pronoun safe for programming in functions.
The !!!
operator now supports all classed objects like factors. It
calls as.list()
on S3 objects and as(x, "list")
on S4 objects.
dots_list()
gains several arguments to control how dots are
collected. You can control the selection of arguments with the same
name with .homonyms
(keep first, last, all, or abort). You can
also elect to preserve empty arguments with .preserve_empty
.
New trace_back()
captures a backtrace. Compared to the base R
traceback, it contains additional structure about the relationship
between frames. It comes with tools for automatically restricting to
frames after a certain environment on the stack, and to simplify
when printing. These backtraces are now recorded in errors thrown by
abort()
(see below).
abort()
gains a parent
argument to specify a parent error. This
is meant for situations where a low-level error is expected
(e.g. download or parsing failed) and you'd like to throw an error
with higher level information. Specifying the low-level error as
parent makes it possible to partition the backtraces based on
ancestry.
Errors thrown with abort()
now embed a backtrace in the condition
object. It is no longer necessary to record a trace with a calling
handler for such errors.
with_abort()
runs expressions in a context where all errors are
promoted to rlang errors and gain a backtrace.
Unhandled errors thrown by abort()
are now automatically saved and
can be retrieved with rlang::last_error()
. The error prints with a
simplified backtrace. Call summary(last_error())
to see the full
backtrace.
New experimental option rlang__backtrace_on_error
to display
backtraces alongside error messages. See ?rlang::abort
for
supported options.
The new signal()
function completes the abort()
, warn()
and
inform()
family. It creates and signals a bare condition.
New interrupt()
function to simulate an user interrupt from R
code.
cnd_signal()
now dispatches messages, warnings, errors and
interrupts to the relevant signalling functions (message()
,
warning()
, stop()
and the C function Rf_onintr()
). This makes
it a good choice to resignal a captured condition.
New cnd_type()
helper to determine the type of a condition
("condition"
, "message"
, "warning"
, "error"
or "interrupt"
).
abort()
, warn()
and inform()
now accepts metadata with ...
.
The data are stored in the condition and can be examined by user
handlers.
Consequently all arguments have been renamed and prefixed with a dot (to limit naming conflicts between arguments and metadata names).
with_handlers()
treats bare functions as exiting handlers
(equivalent to handlers supplied to tryCatch()
). It also supports
the formula shortcut for lambda functions (as in purrr).
with_handlers()
now produces a cleaner stack trace.
The input types of !!!
have been standardised. !!!
is generally
defined on vectors: it takes a vector (typically, a list) and
unquotes each element as a separate argument. The standardisation
makes !!!
behave the same in functions taking dots with list2()
and in quoting functions. !!!
accepts these types:
Lists, pairlists, and atomic vectors. If they have a class, they
are converted with base::as.list()
to allow S3 dispatch.
Following this change, objects like factors can now be spliced
without data loss.
S4 objects. These are converted with as(obj, "list")
before
splicing.
Quoted blocks of expressions, i.e. { }
calls
!!!
disallows:
Quoting functions used to automatically wrap language objects in
lists to make them spliceable. This behaviour is now soft-deprecated
and it is no longer valid to write !!!enquo(x)
. Please unquote
scalar objects with !!
instead.
dots_list()
, enexprs()
and enquos()
gain a .homonyms
argument to control how to treat arguments with the same name.
The default is to keep them. Set it to "first"
or "last"
to keep
only the first or last occurrences. Set it to "error"
to raise an
informative error about the arguments with duplicated names.
enexprs()
and enquos()
now support .ignore_empty = "all"
with named arguments as well (#414).
dots_list()
gains a .preserve_empty
argument. When TRUE
, empty
arguments are stored as missing arguments (see ?missing_arg
).
dots_list()
, enexprs()
and enquos()
gain a .check_assign
argument. When TRUE
, a warning is issued when a <-
call is
detected in ...
. No warning is issued if the assignment is wrapped
in brackets like { a <- 1 }
. The warning lets users know about a
possible typo in their code (assigning instead of matching a
function parameter) and requires them to be explicit that they
really want to assign to a variable by wrapping in parentheses.
lapply(list(quote(foo)), list2)
no longer evaluates foo
(#580).
You can now unquote quosured symbols as LHS of :=
. The symbol is
automatically unwrapped from the quosure.
Quosure methods have been defined for common operations like
==
. These methods fail with an informative error message
suggesting to unquote the quosure (#478, #tidyverse/dplyr#3476).
as_data_pronoun()
now accepts data masks. If the mask has multiple
environments, all of these are looked up when subsetting the pronoun.
Function objects stored in the mask are bypassed.
It is now possible to unquote strings in function position. This is
consistent with how the R parser coerces strings to symbols. These
two expressions are now equivalent: expr("foo"())
and
expr((!!"foo")())
.
Quosures converted to functions with as_function()
now support
nested quosures.
expr_deparse()
(used to print quosures at the console) now escapes
special characters. For instance, newlines now print as "\n"
(#484).
This ensures that the roundtrip parse_expr(expr_deparse(x))
is not
lossy.
new_data_mask()
now throws an error when bottom
is not a child
of top
(#551).
Formulas are now evaluated in the correct environment within
eval_tidy()
. This fixes issues in dplyr and other tidy-evaluation
interfaces.
New functions new_quosures()
and as_quosures()
to create or
coerce to a list of quosures. This is a small S3 class that ensures
two invariants on subsetting and concatenation: that each element is
a quosure and that the list is always named even if only with a
vector of empty strings.
env()
now treats a single unnamed argument as the parent of the
new environment. Consequently, child_env()
is now superfluous and
is now in questioning life cycle.
New current_env()
and current_fn()
functions to retrieve the
current environment or the function being evaluated. They are
equivalent to base::environment()
and base::sys.function()
called without argument.
env_get()
and env_get_list()
gain a default
argument to
provide a default value for non-existing bindings.
env_poke()
now returns the old value invisibly rather than the
input environment.
The new function env_name()
returns the name of an environment.
It always adds the "namespace:" prefix to namespace names. It
returns "global" instead of ".GlobalEnv" or "R_GlobalEnv", "empty"
instead of "R_EmptyEnv". The companion env_label()
is like
env_name()
but returns the memory address for anonymous
environments.
env_parents()
now returns a named list. The names are taken with
env_name()
.
env_parents()
and env_tail()
now stop at the global environment
by default. This can be changed with the last
argument. The empty
environment is always a stopping condition so you can take the
parents or the tail of an environment on the search path without
changing the default.
New predicates env_binding_are_active()
and
env_binding_are_lazy()
detect the kind of bindings in an
environment.
env_binding_lock()
and env_binding_unlock()
allows to lock and
unlock multiple bindings. The predicate env_binding_are_locked()
tests if bindings are locked.
env_lock()
and env_is_locked()
lock an environment or test if
an environment is locked.
env_print()
pretty-prints environments. It shows the contents (up
to 20 elements) and the properties of the environment.
is_scoped()
has been soft-deprecated and renamed to
is_attached()
. It now supports environments in addition to search
names.
env_bind_lazy()
and env_bind_active()
now support quosures.
env_bind_exprs()
and env_bind_fns()
are soft-deprecated and
renamed to env_bind_lazy()
and env_bind_active()
for clarity
and consistency.
env_bind()
, env_bind_exprs()
, and env_bind_fns()
now return
the list of old binding values (or missing arguments when there is
no old value). This makes it easy to restore the original
environment state:
old <- env_bind(env, foo = "foo", bar = "bar")
env_bind(env, !!!old)
env_bind()
now supports binding missing arguments and removing
bindings with zap sentinels. env_bind(env, foo = )
binds a missing
argument and env_bind(env, foo = zap())
removes the foo
binding.
The inherit
argument of env_get()
and env_get_list()
has
changed position. It now comes after default
.
scoped_bindings()
and with_bindings()
can now be called without
bindings.
env_clone()
now recreates active bindings correctly.
env_get()
now evaluates promises and active bindings since these are
internal objects which should not be exposed at the R level (#554)
env_print()
calls get_env()
on its argument, making it easier to
see the environment of closures and quosures (#567).
env_get()
now supports retrieving missing arguments when inherit
is FALSE
.
is_call()
now accepts multiple namespaces. For instance
is_call(x, "list", ns = c("", "base"))
will match if x
is
list()
or if it's base::list()
:
call_modify()
has better support for ...
and now treats it like
a named argument. call_modify(call, ... = )
adds ...
to the call
and call_modify(call, ... = NULL)
removes it.
call_modify()
now preserves empty arguments. It is no longer
necessary to use missing_arg()
to add a missing argument to a
call. This is possible thanks to the new .preserve_empty
option of
dots_list()
.
call_modify()
now supports removing unexisting arguments (#393)
and passing multiple arguments with the same name (#398). The new
.homonyms
argument controls how to treat these arguments.
call_standardise()
now handles primitive functions like ~
properly (#473).
call_print_type()
indicates how a call is deparsed and printed at
the console by R: prefix, infix, and special form.
The call_
functions such as call_modify()
now correctly check
that their input is the right type (#187).
New function zap()
returns a sentinel that instructs functions
like env_bind()
or call_modify()
that objects are to be removed.
New function rep_named()
repeats value along a character vector of
names.
New function exec()
is a simpler replacement to invoke()
(#536). invoke()
has been soft-deprecated.
Lambda functions created from formulas with as_function()
are now
classed. Use is_lambda()
to check a function was created with the
formula shorthand.
is_integerish()
now supports large double values (#578).
are_na()
now requires atomic vectors (#558).
The operator %@%
has now a replacement version to update
attributes of an object (#207).
fn_body()
always returns a {
block, even if the function has a
single expression. For instance fn_body(function(x) do())
returns
quote({ do() })
.
is_string()
now returns FALSE
for NA_character_
.
The vector predicates have been rewritten in C for performance.
The finite
argument of is_integerish()
is now NULL
by
default. Missing values are now considered as non-finite for
consistency with base::is.finite()
.
is_bare_integerish()
and is_scalar_integerish()
gain a finite
argument for consistency with is_integerish()
.
flatten_if()
and squash_if()
now handle primitive functions like
base::is.list()
as predicates.
is_symbol()
now accepts a character vector of names to mach the
symbol against.
parse_exprs()
and parse_quos()
now support character vectors.
Note that the output may be longer than the input as each string may
yield multiple expressions (such as "foo; bar"
).
parse_quos()
now adds the quosures
class to its output.
rlang 0.3.0 introduces a new warning mechanism for soft-deprecated functions and arguments. A warning is issued, but only under one of these circumstances:
library()
call.In addition, deprecation warnings appear only once per session in order to not be disruptive.
Deprecation warnings shouldn't make R CMD check fail for packages
using testthat. However, expect_silent()
can transform the warning
to a hard failure.
.data[[foo]]
is now an unquote operator. This guarantees that
foo
is evaluated in the context rather than the data mask and
makes it easier to treat .data[["bar"]]
the same way as a
symbol. For instance, this will help ensuring that group_by(df, .data[["name"]])
and group_by(df, name)
produce the same column
name.
Automatic naming of expressions now uses a new deparser (still
unexported) instead of quo_text()
. Following this change,
automatic naming is now compatible with all object types (via
pillar::type_sum()
if available), prevents multi-line names, and
ensures name
and .data[["name"]]
are given the same default
name.
Supplying a name with !!!
calls is soft-deprecated. This name is
ignored because only the names of the spliced vector are applied.
Quosure lists returned by quos()
and enquos()
now have "list-of"
behaviour: the types of new elements are checked when adding objects
to the list. Consequently, assigning non-quosure objects to quosure
lists is now soft-deprecated. Please coerce to a bare list with
as.list()
beforehand.
as_quosure()
now requires an explicit environment for symbols and
calls. This should typically be the environment in which the
expression was created.
names()
and length()
methods for data pronouns are deprecated.
It is no longer valid to write names(.data)
or length(.data)
.
Using as.character()
on quosures is soft-deprecated (#523).
Using get_env()
without supplying an environment is now
soft-deprecated. Please use current_env()
to retrieve the current
environment.
The frame and stack API is soft-deprecated. Some of the
functionality has been replaced by trace_back()
.
The new_vector_along()
family is soft-deprecated because these
functions are longer to type than the equivalent rep_along()
or
rep_named()
calls without added clarity.
Passing environment wrappers like formulas or functions to env_
functions is now soft-deprecated. This internal genericity was
causing confusion (see issue #427). You should now extract the
environment separately before calling these functions.
This change concerns env_depth()
, env_poke_parent()
,
env_parent<-
, env_tail()
, set_env()
, env_clone()
,
env_inherits()
, env_bind()
, scoped_bindings()
,
with_bindings()
, env_poke()
, env_has()
, env_get()
,
env_names()
, env_bind_exprs()
and env_bind_fns()
.
cnd_signal()
now always installs a muffling restart for
non-critical conditions. Consequently the .mufflable
argument has
been soft-deprecated and no longer has any effect.
Deprecated functions and arguments issue a warning inconditionally, but only once per session.
Calling UQ()
and UQS()
with the rlang namespace qualifier is
deprecated as of rlang 0.3.0. Just use the unqualified forms
instead:
# Bad
rlang::expr(mean(rlang::UQ(var) * 100))
# Ok
rlang::expr(mean(UQ(var) * 100))
# Good
rlang::expr(mean(!!var * 100))
Although soft-deprecated since rlang 0.2.0, UQ()
and UQS()
can still be used for now.
The call
argument of abort()
and condition constructors is now
deprecated in favour of storing full backtraces.
The .standardise
argument of call_modify()
is deprecated. Please
use call_standardise()
beforehand.
The sentinel
argument of env_tail()
has been deprecated and
renamed to last
.
Defunct functions and arguments throw an error when used.
as_dictionary()
is now defunct.
The experimental function rst_muffle()
is now defunct. Please use
cnd_muffle()
instead. Unlike its predecessor, cnd_muffle()
is not
generic. It is marked as a calling handler and thus can be passed
directly to with_handlers()
to muffle specific conditions (such as
specific subclasses of warnings).
cnd_inform()
, cnd_warn()
and cnd_abort()
are retired and
defunct. The old cnd_message()
, cnd_warning()
, cnd_error()
and
new_cnd()
constructors deprecated in rlang 0.2.0 are now defunct.
Modifying a condition with cnd_signal()
is defunct. In addition,
creating a condition with cnd_signal()
is soft-deprecated, please
use the new function [signal()] instead.
inplace()
has been renamed to calling()
to follow base R
terminology more closely.
We are no longer convinced these functions are the right approach but we do not have a precise alternative yet.
The functions from the restart API are now in the questioning lifecycle stage. It is not clear yet whether we want to recommend restarts as a style of programming in R.
prepend()
and modify()
are in the questioning stage, as well as
as_logical()
, as_character()
, etc. We are still figuring out
what vector tools belong in rlang.
flatten()
, squash()
and their atomic variants are now in the
questioning lifecycle stage. They have slightly different semantics
than the flattening functions in purrr and we are currently
rethinking our approach to flattening with the new typing facilities
of the vctrs package.
This is a maintenance release that fixes several garbage collection protection issues.
This is a maintenance release that fixes several tidy evaluation issues.
Functions with tidy dots support now allow splicing atomic vectors.
Quosures no longer capture the current srcref
.
Formulas are now evaluated in the correct environment by
eval_tidy()
. This fixes issues in dplyr and other tidy-evaluation
interfaces.
This release of rlang is mostly an effort at polishing the tidy evaluation framework. All tidy eval functions and operators have been rewritten in C in order to improve performance. Capture of expression, quasiquotation, and evaluation of quosures are now vastly faster. On the UI side, many of the inconveniences that affected the first release of rlang have been solved:
The !!
operator now has the precedence of unary +
and -
which
allows a much more natural syntax: !!a > b
only unquotes a
rather than the whole a > b
expression.
enquo()
works in magrittr pipes: mtcars %>% select(!!enquo(var))
.
enquos()
is a variant of quos()
that has a more natural
interface for capturing multiple arguments and ...
.
See the first section below for a complete list of changes to the tidy evaluation framework.
This release also polishes the rlang API. Many functions have been
renamed as we get a better feel for the consistency and clarity of the
API. Note that rlang as a whole is still maturing and some functions
are even experimental. In order to make things clearer for users of
rlang, we have started to develop a set of conventions to document the
current stability of each function. You will now find "lifecycle"
sections in documentation topics. In addition we have gathered all
lifecycle information in the ?rlang::lifecycle
help page. Please
only use functions marked as stable in your projects unless you are
prepared to deal with occasional backward incompatible updates.
The backend for quos()
, exprs()
, list2()
, dots_list()
, etc
is now written in C. This greatly improve the performance of dots
capture, especially with the splicing operator !!!
which now
scales much better (you'll see a 1000x performance gain in some
cases). The unquoting algorithm has also been improved which makes
enexpr()
and enquo()
more efficient as well.
The tidy eval !!
operator now binds tightly. You no longer have to
wrap it in parentheses, i.e. !!x > y
will only unquote x
.
Technically the !!
operator has the same precedence as unary -
and +
. This means that !!a:b
and !!a + b
are equivalent to
(!!a):b
and (!!a) + b
. On the other hand !!a^b
and !!a$b
are
equivalent to!!(a^b)
and !!(a$b)
.
The print method for quosures has been greatly improved. Quosures no
longer appear as formulas but as expressions prefixed with ^
;
quosures are colourised according to their environment; unquoted
objects are displayed between angular brackets instead of code
(i.e. an unquoted integer vector is shown as <int: 1, 2>
rather
than 1:2
); unquoted S3 objects are displayed using
pillar::type_sum()
if available.
New enquos()
function to capture arguments. It treats ...
the
same way as quos()
but can also capture named arguments just like
enquo()
, i.e. one level up. By comparison quos(arg)
only
captures the name arg
rather than the expression supplied to the
arg
argument.
In addition, enexprs()
is like enquos()
but like exprs()
it
returns bare expressions. And ensyms()
expects strings or symbols.
It is now possible to use enquo()
within a magrittr pipe:
select_one <- function(df, var) {
df %>% dplyr::select(!!enquo(var))
}
Technically, this is because enquo()
now also captures arguments
in parents of the current environment rather than just in the
current environment. The flip side of this increased flexibility is
that if you made a typo in the name of the variable you want to
capture, and if an object of that name exists anywhere in the parent
contexts, you will capture that object rather than getting an error.
quo_expr()
has been renamed to quo_squash()
in order to better
reflect that it is a lossy operation that flattens all nested
quosures.
!!!
now accepts any kind of objects for consistency. Scalar types
are treated as vectors of length 1. Previously only symbolic objects
like symbols and calls were treated as such.
ensym()
is a new variant of enexpr()
that expects a symbol or a
string and always returns a symbol. If a complex expression is
supplied it fails with an error.
exprs()
and quos()
gain a .unquote_names
arguments to switch
off interpretation of :=
as a name operator. This should be useful
for programming on the language targetting APIs such as
data.table.
exprs()
gains a .named
option to auto-label its arguments (#267).
Functions taking dots by value rather than by expression
(e.g. regular functions, not quoting functions) have a more
restricted set of unquoting operations. They only support :=
and
!!!
, and only at top-level. I.e. dots_list(!!! x)
is valid but
not dots_list(nested_call(!!! x))
(#217).
Functions taking dots with list2()
or dots_list()
now support
splicing of NULL
values. !!! NULL
is equivalent to !!! list()
(#242).
Capture operators now support evaluated arguments. Capturing a
forced or evaluated argument is exactly the same as unquoting that
argument: the actual object (even if a vector) is inlined in the
expression. Capturing a forced argument occurs when you use
enquo()
, enexpr()
, etc too late. It also happens when your
quoting function is supplied to lapply()
or when you try to quote
the first argument of an S3 method (which is necessarily evaluated
in order to detect which class to dispatch to). (#295, #300).
Parentheses around !!
are automatically removed. This makes the
generated expression call cleaner: (!! sym("name"))(arg)
. Note
that removing the parentheses will never affect the actual
precedence within the expression as the parentheses are only useful
when parsing code as text. The parentheses will also be added by R
when printing code if needed (#296).
Quasiquotation now supports !!
and !!!
as functional forms:
expr(`!!`(var))
quo(call(`!!!`(var)))
This is consistent with the way native R operators parses to
function calls. These new functional forms are to be preferred to
UQ()
and UQS()
. We are now questioning the latter and might
deprecate them in a future release.
The quasiquotation parser now gives meaningful errors in corner cases to help you figure out what is wrong.
New getters and setters for quosures: quo_get_expr()
,
quo_get_env()
, quo_set_expr()
, and quo_set_env()
. Compared to
get_expr()
etc, these accessors only work on quosures and are
slightly more efficient.
quo_is_symbol()
and quo_is_call()
now take the same set of
arguments as is_symbol()
and is_call()
.
enquo()
and enexpr()
now deal with default values correctly (#201).
Splicing a list no longer mutates it (#280).
The new functions cnd_warn()
and cnd_inform()
transform
conditions to warnings or messages before signalling them.
cnd_signal()
now returns invisibly.
cnd_signal()
and cnd_abort()
now accept character vectors to
create typed conditions with several S3 subclasses.
is_condition()
is now properly exported.
Condition signallers such as cnd_signal()
and abort()
now accept
a call depth as call
arguments. This allows plucking a call from
further up the call stack (#30).
New helper catch_cnd()
. This is a small wrapper around
tryCatch()
that captures and returns any signalled condition. It
returns NULL
if none was signalled.
cnd_abort()
now adds the correct S3 classes for error
conditions. This fixes error catching, for instance by
testthat::expect_error()
.
env_get_list()
retrieves muliple bindings from an environment into
a named list.
with_bindings()
and scoped_bindings()
establish temporary
bindings in an environment.
is_namespace()
is a snake case wrapper around isNamespace()
.
New functions inherits_any()
, inherits_all()
, and
inherits_only()
. They allow testing for inheritance from multiple
classes. The _any
variant is equivalent to base::inherits()
but
is more explicit about its behaviour. inherits_all()
checks that
all classes are present in order and inherits_only()
checks that
the class vectors are identical.
New fn_fmls<-
and fn_fmls_names<-
setters.
New function experimental function chr_unserialise_unicode()
for
turning characters serialised to unicode point form
(e.g. <U+xxxx>
) to UTF-8. In addition, as_utf8_character()
now
translates those as well. (@krlmlr)
expr_label()
now supports quoted function definition calls (#275).
call_modify()
and call_standardise()
gain an argument to specify
an environment. The call definition is looked up in that environment
when the call to modify or standardise is not wrapped in a quosure.
is_symbol()
gains a name
argument to check that that the symbol
name matches a string (#287).
New rlang_box
class. Its purpose is similar to the AsIs
class
from base::I()
, i.e. it protects a value temporarily. However it
does so by wrapping the value in a scalar list. Use new_box()
to
create a boxed value, is_box()
to test for a boxed value, and
unbox()
to unbox it. new_box()
and is_box()
accept optional
subclass.
The vector constructors such as new_integer()
,
new_double_along()
etc gain a names
argument. In the case of the
_along
family it defaults to the names of the input vector.
When nested quosures are evaluated with eval_tidy()
, the .env
pronoun now correctly refers to the current quosure under evaluation
(#174). Previously it would always refer to the environment of the
outermost quosure.
as_pairlist()
(part of the experimental API) now supports NULL
and objects of type pairlist (#397).
Fixed a performance bug in set_names()
that caused a full copy of
the vector names (@jimhester, #366).
The rlang API is maturing and still in flux. However we have made an
effort to better communicate what parts are stable. We will not
introduce breaking changes for stable functions unless the payoff for
the change is worth the trouble. See ?rlang::lifecycle
for the
lifecycle status of exported functions.
The particle "lang" has been renamed to "call":
lang()
has been renamed to call2()
.new_language()
has ben renamed to new_call()
.is_lang()
has been renamed to is_call()
. We haven't replaced
the is_unary_lang()
and is_binary_lang()
because they are
redundant with the n
argument of is_call()
.lang_fn()
, lang_name()
,
lang_args()
etc are soft-deprecated and renamed with call_
prefix.In rlang 0.1 calls were called "language" objects in order to follow
the R type nomenclature as returned by base::typeof()
. We wanted
to avoid adding to the confusion between S modes and R types. With
hindsight we find it is better to use more meaningful type names.
We now use the term "data mask" instead of "overscope". We think data mask is a more natural name in the context of R. We say that that objects from user data mask objects in the current environment. This makes reference to object masking in the search path which is due to the same mechanism (in technical terms, lexical scoping with hierarchically nested environments).
Following this new terminology, the new functions as_data_mask()
and new_data_mask()
replace as_overscope()
and
new_overscope()
. as_data_mask()
has also a more consistent
interface. These functions are only meant for developers of tidy
evaluation interfaces.
We no longer require a data mask (previously called overscope) to be
cleaned up after evaluation. overscope_clean()
is thus
soft-deprecated without replacement.
!!
now binds tightly in order to match intuitive parsing of tidy
eval code, e.g. !! x > y
is now equivalent to (!! x) > y
. A
corollary of this new syntax is that you now have to be explicit
when you want to unquote the whole expression on the right of !!
.
For instance you have to explicitly write !! (x > y)
to unquote
x > y
rather than just x
.
UQ()
, UQS()
and :=
now issue an error when called
directly. The previous definitions caused surprising results when
the operators were invoked in wrong places (i.e. not in quasiquoted
arguments).
The prefix form `!!`()
is now an alias to !!
rather than
UQE()
. This makes it more in line with regular R syntax where
operators are parsed as regular calls, e.g. a + b
is parsed as `+`(a, b)
and both forms are completely equivalent. Also the
prefix form `!!!`()
is now equivalent to !!!
.
UQE()
is now deprecated in order to simplify the syntax of
quasiquotation. Please use !! get_expr(x)
instead.
expr_interp()
now returns a formula instead of a quosure when
supplied a formula.
is_quosureish()
and as_quosureish()
are deprecated. These
functions assumed that quosures are formulas but that is only an
implementation detail.
new_cnd()
is now cnd()
for consistency with other constructors.
Also, cnd_error()
, cnd_warning()
and cnd_message()
are now
error_cnd()
, warning_cnd()
and message_cnd()
to follow our
naming scheme according to which the type of output is a suffix
rather than a prefix.
is_node()
now returns TRUE
for calls as well and is_pairlist()
does not return TRUE
for NULL
objects. Use is_node_list()
to
determine whether an object either of type pairlist
or NULL
.
Note that all these functions are still experimental.
set_names()
no longer automatically splices lists of character
vectors as we are moving away from automatic splicing semantics.
Calling the functional forms of unquote operators with the rlang
namespace qualifier is soft-deprecated. UQ()
and UQS()
are not
function calls so it does not make sense to namespace them.
Supporting namespace qualifiers complicates the implementation of
unquotation and is misleading as to the nature of unquoting (which
are syntactic operators at quotation-time rather than function calls
at evaluation-time).
We are now questioning UQ()
and UQS()
as functional forms of
!!
. If !!
and !!!
were native R operators, they would parse
to the functional calls `!!`()
and `!!!`()
. This is now
the preferred way to unquote with a function call rather than with
the operators. We haven't decided yet whether we will deprecate
UQ()
and UQS()
in the future. In any case we recommend using the
new functional forms.
parse_quosure()
and parse_quosures()
are soft-deprecated in
favour of parse_quo()
and parse_quos()
. These new names are
consistent with the rule that abbreviated suffixes indicate the
return type of a function. In addition the new functions require their
callers to explicitly supply an environment for the quosures.
Using f_rhs()
and f_env()
on quosures is soft-deprecated. The
fact that quosures are formulas is an implementation detail that
might change in the future. Please use quo_get_expr()
and
quo_get_env()
instead.
quo_expr()
is soft-deprecated in favour of quo_squash()
.
quo_expr()
was a misnomer because it implied that it was a mere
expression acccessor for quosures whereas it was really a lossy
operation that squashed all nested quosures.
With the renaming of the lang
particle to call
, all these
functions are soft-deprecated: lang()
, is_lang()
, lang_fn()
,
lang_name()
, lang_args()
.
In addition, lang_head()
and lang_tail()
are soft-deprecated
without replacement because these are low level accessors that are
rarely needed.
as_overscope()
is soft-deprecated in favour of as_data_mask()
.
The node setters were renamed from mut_node_
prefix to
node_poke_
. This change follows a new naming convention in rlang
where mutation is referred to as "poking".
splice()
is now in questioning stage as it is not needed given the
!!!
operator works in functions taking dots with dots_list()
.
lgl_len()
, int_len()
etc have been soft-deprecated and renamed
with new_
prefix, e.g. new_logical()
and new_integer()
. This
is for consistency with other non-variadic object constructors.
ll()
is now an alias to list2()
. This is consistent with the new
call2()
constructor for calls. list2()
and call2()
are
versions of list()
and call()
that support splicing of lists
with !!!
. ll()
remains around as a shorthand for users who like
its conciseness.
Automatic splicing of lists in vector constructors (e.g. lgl()
,
chr()
, etc) is now soft-deprecated. Please be explicit with the
splicing operator !!!
.
This is a maintenance release in anticipation of a forthcoming
change to R's C API (use MARK_NOT_MUTABLE()
instead of
SET_NAMED()
).
New function is_reference()
to check whether two objects are one
and the same.
eval_tidy()
no longer maps over lists but returns them literally.
This behaviour is an overlook from past refactorings and was never
documented.This hotfix release makes rlang compatible with the R 3.1 branch.
This release includes two important fixes for tidy evaluation:
Bare formulas are now evaluated in the correct environment in tidyeval functions.
enquo()
now works properly within compiled functions. Before this
release, constants optimised by the bytecode compiler couldn't be
enquoted.
The new_environment()
constructor creates a child of the empty
environment and takes an optional named list of data to populate it.
Compared to env()
and child_env()
, it is meant to create
environments as data structures rather than as part of a scope
hierarchy.
The new_call()
constructor creates calls out of a callable
object (a function or an expression) and a pairlist of arguments. It
is useful to avoid costly internal coercions between lists and
pairlists of arguments.
env_child()
's first argument is now .parent
instead of parent
.
mut_
setters like mut_attrs()
and environment helpers like
env_bind()
and env_unbind()
now return their (modified) input
invisibly. This follows the tidyverse convention that functions
called primarily for their side effects should return their input
invisibly.
is_pairlist()
now returns TRUE
for NULL
. We added is_node()
to test for actual pairlist nodes. In other words, is_pairlist()
tests for the data structure while is_node()
tests for the type.
env()
and env_child()
can now get arguments whose names start
with .
. Prior to this fix, these arguments were partial-matching
on env_bind()
's .env
argument.
The internal replace_na()
symbol was renamed to avoid a collision
with an exported function in tidyverse. This solves an issue
occurring in old versions of R prior to 3.3.2 (#133).
Initial release.