Changelog
Source:NEWS.md
rlang 1.1.4
CRAN release: 2024-06-04
Added missing C level
r_dyn_raw_push_back()
andr_dyn_chr_push_back()
utilities (#1699).last_trace()
hyperlinks now use the modernx-r-run
format (#1678).
rlang 1.1.3
CRAN release: 2024-01-10
Fix for CRAN checks.
%||%
is now reexported from base on newer R versions. This avoids conflict messages when attaching or importing rlang.
rlang 1.1.2
CRAN release: 2023-11-04
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 andis.atomic(NULL)
(#1655)Performance improvement in
.rlang_cli_compat()
(#1657).
rlang 1.1.1
CRAN release: 2023-04-28
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 handlesI()
input literally inarg
(#1607, @simonpcouch).parse_expr()
andparse_exprs()
are now faster whengetOption("keep.source")
isTRUE
(#1603).
rlang 1.1.0
CRAN release: 2023-03-14
Life cycle changes
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 ofpurrr::list_flatten()
andpurrr::list_c()
.child_env()
is deprecated in favour ofenv()
which has supported creating child environments for several years now.
Main new features
last_error()
andoptions(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()
, andlast_messages()
now support knitr documents.New
rlang_backtrace_on_warning_report
global option. This is useful in conjunction withglobal_entrace()
to get backtraces on warnings inside RMarkdown documents.global_entrace()
andentrace()
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()
, andinform()
gain an.inherit
parameter. This controls whetherparent
is inherited. IfFALSE
,cnd_inherits()
andtry_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 toFALSE
(#1573). try_fetch()
now looks up condition classes across chained errors (#1534). This makestry_fetch()
insensitive to changes of implementation or context of evaluation that cause a classed error to suddenly get chained to a contextual error.englue()
gainedenv
,error_arg
, anderror_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]>
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.
Miscellaneous fixes and features
New
check_data_frame()
andcheck_logical()
functions instandalone-types-check.R
(#1587, @mgirlich).Added
allow_infinite
argument tocheck_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()
instandalone-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 functionR_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()
andr_lgl_which()
helpers are now faster (#1577, with contributions from @mgirlich).rlang is now compliant with
-Wstrict-prototypes
as requested by CRAN (#1508).
rlang 1.0.6
CRAN release: 2022-09-24
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).
rlang 1.0.4
CRAN release: 2022-07-12
is_installed()
no longer throws an error with irregular package names.is_installed()
andcheck_installed()
now properly detect that the base package is installed on older versions of R (#1434).
rlang 1.0.3
CRAN release: 2022-06-27
-
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 ofabort()
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 theheader
field and acts as acnd_header()
method invoked when the message is displayed.New
obj_type_oo()
function incompat-obj-type.R
(#1426).friendly_type_of()
fromcompat-obj-type.R
(formerlycompat-friendly-type.R
) is nowobj_type_friendly()
.options(backtrace_on_error = "collapse")
andprint(trace, simplify = "collapse")
are deprecated. They fall back to"none"
with a warning.call_match()
now better handles...
whendots_expand = FALSE
.list2(!!!x)
is now faster whenx
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 allowscli::cli_abort()
to wrapabort()
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()
andreset_message_verbosity()
functions. These reset the verbosity of messages signalled withwarn()
andinform()
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-alltryCatch(error = )
expressions (#1402, tidyverse/ggplot2#4845).arg_match()
andarg_match0()
now mention the correct call in case of type error (#1388).abort()
andinform()
now print messages tostdout
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 supportsstyle_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.
rlang 1.0.2
CRAN release: 2022-03-04
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 inabort(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()
orcli::format_warning
) when the installed version of cli is too old (#1367, tidyverse/dplyr#6189).Fixed an OOB subsetting error in
abort()
.
rlang 1.0.1
CRAN release: 2022-02-03
New
rlang_call_format_srcrefs
global option (#1349). Similar torlang_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 helpsabort()
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 andcall
points to the condition setup frame (e.g.withCallingHandlers()
ortry_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
, andfooter
condition fields.eval_tidy()
calls are no longer mentioned in error messages.
rlang 1.0.0
CRAN release: 2022-01-26
Major changes
This release focuses on the rlang errors framework and features extensive changes to the display of error messages.
abort()
now displays errors as fully bulleted lists. Error headers are displayed with a!
prefix. See https://rlang.r-lib.org/reference/topic-condition-customisation.html to customise the display of error messages.abort()
now displays a full chain of messages when errors are chained with theparent
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 acall
argument that you can set tocaller_env()
orparent.frame()
when used in a helper function. The function call corresponding to this environment is retrieved and stored in the condition. cli formatting is now supported. Use
cli::cli_abort()
to get advanced formatting of error messages, including indented bulleted lists. See https://rlang.r-lib.org/reference/topic-condition-formatting.html.-
New
try_fetch()
function for error handling. We recommend to use it for chaining errors. It mostly works liketryCatch()
with a few important differences.Compared to
tryCatch()
,try_fetch()
preserves the call stack. This allows full backtrace capture and allowsrecover()
to reach the error site.Compared to
withCallingHandler()
,try_fetch()
is able to handle stack overflow errors (this requires R 4.2, unreleased at the time of writing).
The tidy eval documentation has been fully rewritten to reflect current practices. Access it through the “Tidy evaluation” and “Metaprogramming” menus on https://rlang.r-lib.org.
Breaking changes
-
The
.data
object exported by rlang now fails when subsetted instead of returningNULL
. 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 theby
argument ofdplyr::join()
is not data-masked. Previouslydplyr::join(by = .data$foo)
would silently be interpreted asdplyr::join(by = NULL)
. This is now an error.Another issue is using
.data
insideggplot2::labs(...)
. This is not allowed sincelabs()
isn’t data-masked. -
call_name()
now returnsNULL
instead of"::"
for calls of the formfoo::bar
.We’ve noticed some packages do not check for
NULL
results fromcall_name()
. Note that many complex calls such asfoo()()
,foo$bar()
don’t have a “name” and cause aNULL
result. This is why you should always check forNULL
results when usingcall_name()
.We’ve added the function
is_call_simple()
to make it easier to work safely withcall_name()
. The invariant is thatcall_name()
always returns a string whenis_call_simple()
returnsTRUE
. Conversely it always returnsNULL
whenis_call_simple()
retunsFALSE
. -
is_expression()
now returnsFALSE
for manually constructed expressions that can’t be created by the parser. It used to returnTRUE
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 toas_function()
and sometimes there is no obvious user environment. The support for strings should be considered a convenience for end users only, not for programmers.Since environment forwarding is easy to mess up, and since the feature is aimed towards end users,
as_function()
now defaults to the global environment. Supply an environment explicitly if that is not correct in your case. with_handlers()
,call_fn()
, andfriendly_type()
are deprecated.The
action
argument ofcheck_dots_used()
,check_dots_unnamed()
, andcheck_dots_empty()
is deprecated in favour of the newerror
argument which takes an error handler.Many functions deprecated in rlang 0.2.0 and 0.3.0 have been removed from the package.
Fixes and features
tidyeval
New
englue()
operator to allow string-embracing outside of dynamic dots (#1172).New
data_sym()
anddata_syms()
functions to create calls of the form.data$foo
..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 liketibble()
,mutate()
, etc.The
{{
operator is now detected more strictly (#1087). If additional arguments are supplied through{
, it is no longer interpreted as an injection operator.The
.ignore_empty
argument ofenexprs()
andenquos()
no longer treats named arguments supplied through...
as empty, consistently withexprs()
andquos()
(#1229).Fixed a hang when a quosure inheriting from a data mask is evaluated in the mask again.
Fixed performance issue when splicing classes that explicitly inherit from list with
!!!
(#1140, r-lib/vctrs#1170).Attributes of quosure lists are no longer modified by side effect (#1142).
enquo()
,enquos()
and variants now support numbered dots like..1
(#1137).Fixed a bug in the AST rotation algorithm that caused the
!!
operator to unexpectedly mutate injected objects (#1103).Fixed AST rotation issue with
!!
involving binary operators (#1125).
rlang errors
try_fetch()
is a flexible alternative to bothtryCatch()
andwithCallingHandlers()
(#503). It is also more efficient thantryCatch()
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 enableslast_error()
,last_warnings()
,last_messages()
, andbacktrace_on_error
support for all conditions.New
global_handle()
function to install a default configuration of error handlers. This currently callsglobal_entrace()
andglobal_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 inbase::stop()
. The call is only displayed if it is a simple expression (e.g. no inlined function) and the arguments are not displayed to avoid distracting from the error message. The message is formatted with the tidyverse style (code
formatting by the cli package if available).The source location is displayed (as in
base::stop()
) ifcall
carries a source reference. Source locations are not displayed when testthat is running to avoid brittle snapshots.Error headers are always displayed on their own line, with a
"!"
bullet prefix.
See https://rlang.r-lib.org/reference/topic-condition-customisation.html to customise this new display.
The display of chained errors created with the
parent
argument ofabort()
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 withlast_error()
) has been improved:- Display calls if present.
- Chained errors are displayed more clearly.
inform()
andwarn()
messages can now be silenced with the global optionsrlib_message_verbosity
andrlib_warning_verbosity
.abort()
now outputs error messages tostdout
in interactive sessions, following the same approach asinform()
.-
Errors, warnings, and messages generated from rlang are now formatted with cli. This means in practice that long lines are width-wrapped to the terminal size and user themes are applied. This is currently only the case for rlang messages.
This special formatting is not applied when
abort()
,warn()
, andinform()
are called from another namespace than rlang. See https://rlang.r-lib.org/reference/topic-condition-formatting.html if you’d like to use cli to format condition messages in your package. -
format_error_bullets()
(used as a fallback instead of cli) now treats:- Unnamed elements as unindented line breaks (#1130)
- Elements named
"v"
as green ticks (@rossellhayes) - Elements named
" "
as indented line breaks - Elements named
"*"
as normal bullets - Elements named
"!"
as warning bullets
For convenience, a fully unnamed vector is interpreted as a vector of
"*"
bullets. abort()
gains a.internal
argument. When set toTRUE
, a footer bullet is added tomessage
to let the user know that the error is internal and that they should report it to the package authors.abort()
,warn()
, andinform()
gain abody
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 theError:
prefix. These methods are implemented as wrappers aroundcnd_message()
.header
andfooter
methods can now be stored as closures in condition fields of the same name.cnd_message()
gains aprefix
argument to print the message with a full prefix, includingcall
field if present and parent messages if the condition is chained.cnd_message()
gains aninherit
argument to control whether to print the messages of parent errors.Condition constructors now check for duplicate field names (#1268).
cnd_footer()
now returns thefooter
field by default, if any.warn()
andinform()
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 runninglast_error()
.Added
is_error()
,is_warning()
, andis_message()
predicates (#1220).interrupt()
no longer fails when interrupts are suspended (#1224).warn()
now temporarily sets thewarning.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).
Backtraces
entrace()
andglobal_entrace()
now log warnings and messages with backtraces attached. Runlast_warnings()
orlast_messages()
to inspect the warnings or messages emitted during the last command.Internal errors now include a winch backtrace if installed. The user is invited to install it if not installed.
-
Display of rlang backtraces for expected errors in dynamic reports (chunks where
error = TRUE
in knitted documents and RStudio notebooks) is now controlled by therlang_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 toFALSE
) is still controlled byrlang_backtrace_on_error
. The
last_error()
reminder is no longer displayed in RStudio notebooks.-
A
knitr::sew()
method is registered forrlang_error
. This makes it possible to consultlast_error()
(the call must occur in a different chunk than the error) and to setrlang_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 fortrace_back()
now detects when backtraces are created within knitr. If the option is not set, its default value becomesknitr::knit_global()
when knitr is in progress (as determined fromknitr.in.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).
Argument intake
arg_match()
gains amultiple
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 thanforce()
(#1118).-
check_dots_empty()
,check_dots_used()
, andcheck_dots_unnamed()
have been moved from ellipsis to rlang. The ellipsis package is deprecated and will eventually be archived.We have added
check_dots_empty0()
. It has a different UI but is almost as efficient as checking formissing(...)
. Use this in very low level functions where a couple microseconds make a difference. The
arg_nm
argument ofarg_match0()
must now be a string or symbol.arg_match()
now mentions the supplied argument (#1113).is_installed()
andcheck_installed()
gain aversion
argument (#1165).check_installed()
now consults therlib_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 classrlib_error_package_not_found
with arlib_restart_package_not_found
restart. This allows calling handlers to install the required packages and restart the check (#1150).is_installed()
andcheck_installed()
now support DESCRIPTION-style version requirements like"rlang (>= 1.0)"
. They also gainversion
andcompare
arguments to supply requirements programmatically.check_installed()
gains anaction
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).
R APIs
on_load()
andrun_on_load()
lets you run.onLoad()
expressions from any file of your package.on_package_load()
runs expressions when another package is loaded. (#1284)-
The new predicate
is_call_simple()
indicates whether a call has a name and/or a namespace. It provides two invariants:If
is_call_simple(x)
isTRUE
,call_name()
always returns a string.If
is_call_simple(x, ns = TRUE)
isTRUE
,call_ns()
always returns a string.
call_name()
andcall_ns()
now returnNULL
with calls of the formfoo::bar
(#670).New
current_call()
,caller_call()
, andframe_call()
accessors. Newframe_fn()
accessor.env_has()
and the corresponding C-level function no longer force active bindings (#1292).New
names2<-
replacement function that never adds missing values when names don’t have names (#1301).zap_srcref()
now preserves attributes of closures.Objects headers (as printed by
last_error()
,env_print()
, …) are now formatted using thecls
class of the cli package.as_function()
gainsarg
andcall
arguments to provide contextual information about erroring inputs.is_expression()
now returnsFALSE
for manually constructed expressions that cannot be created by the R parser.New C callable
rlang_env_unbind()
. This is a wrapper aroundR_removeVarFromFrame()
on R >= 4.0.0. On older R this wraps the R functionbase::rm()
. Unlikerm()
, this function does not warn (nor throw) when a binding does not exist.friendly_type_of()
now supports missing arguments.env_clone()
now properly clones active bindings and avoids forcing promises (#1228). On R < 4.0, promises are still forced.Fixed an
s3_register()
issue when the registering package is a dependency of the package that exports the generic (#1225).Added
compat-vctrs.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 includespluck*
helpers; these used a defintion of pluck that predated purrr (#1159).*_cpl()
has also been removed. Themap*
wrappers now callas_function()
so that you can pass short anonymous functions that use~
(#1157).exprs_auto_name()
gains arepair_auto
argument to make automatic names unique (#1116).The
.named
argument ofdots_list()
can now be set toNULL
to give the result default names. With this option, fully unnamed inputs produce a fully unnamed result withNULL
names instead of a character vector of minimal""
names (#390).is_named2()
is a variant ofis_named()
that always returnsTRUE
for empty vectors (#191). It tests for the property that each element of a vector is named rather than the presence of anames
attribute.New
rlib_bytes
class imported from the bench package (#1117). It prints and parses human-friendly sizes.The
env
argument ofas_function()
now defaults to the global environment. Its previous default was the caller ofas_function()
, which was rarely the correct environment to look in. Since it’s hard to remember to pass the user environment and it’s sometimes tricky to keep track of it, it’s best to consider string lookup as a convenience for end users, not for developers (#1170).s3_register()
no longer fails when generic does not exist. This prevents failures when users don’t have all the last versions of packages (#1112).Formulas are now deparsed according to the tidyverse style guide (
~symbol
without space and~ expression()
with a space).New
hash_file()
, complementinghash()
, to generate 128-bit hashes for the data within a file without loading it into R (#1134).New
env_cache()
function to retrieve a value or create it with a default if it doesn’t exist yet (#1081).env_get()
andenv_get_list()
gain alast
argument. Lookup stops in that environment. This can be useful in conjunction withbase::topenv()
.-
New
call_match()
function. It is likematch.call()
but also supports matching missing arguments to their defaults in the function definition (#875).call_standardise()
is deprecated in favour ofcall_match()
. expr_deparse()
now properly escapes\
characters in symbols, argument names, and vector names (#1160).friendly_type_of()
(fromcompat-friendly-type.R
) now supports matrices and arrays (#141).Updated
env_print()
to useformat_error_bullets()
and consistent tidyverse style (#1154).set_names()
now recycles names of size 1 to the size of the input, following the tidyverse recycling rules.is_bare_formula()
now handles thescoped
argument consistently. The default has been changed toTRUE
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 prefix0x
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 namerlang_xxh3_64bits()
.
rlang 0.4.10
CRAN release: 2020-12-30
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. Unlikeis_installed()
, it asks the user whether to install missing packages. If the user accepts, the packages are installed withpak::pkg_install()
if available, orutils::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).
rlang 0.4.9
CRAN release: 2020-11-25
New features
inject()
evaluates its argument with!!
,!!!
, and{{
support.New
enquo0()
andenquos0()
operators for defusing function arguments without automatic injection (unquotation).format_error_bullets()
is no longer experimental. Themessage
arguments ofabort()
,warn()
, andinform()
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()
andenv_is_browsed()
functions.env_browse()
is equivalent to evaluatingbrowser()
within an environment. It sets the environment to be persistently browsable (or unsets it ifvalue = 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).
Bugfixes and improvements
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), andwith_handlers()
(#518) now propagate visibility.cnd_signal()
now ignoresNULL
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 anoptions(error = )
handler (#1052, rstudio/bookdown#920).next
andbreak
are now properly deparsed as nullary operators.
rlang 0.4.8
CRAN release: 2020-10-08
Backtraces now include native stacks (e.g. from C code) when the winch package is installed and
rlang_trace_use_winch
is set toTRUE
(@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).
rlang 0.4.7
CRAN release: 2020-07-09
cnd_muffle()
now returnsFALSE
instead of failing if the condition is not mufflable (#1022).warn()
andinform()
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()
, andenv_get_list()
have been rewritten in C.env_poke()
now supportszap()
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 byexpr_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 evaluatesx
multiple times (#981).is_installed()
now properly handles apkg
argument of length > 1. Before this it silently tested the first element ofpkg
only and thus always returnedTRUE
if the first package was installed regardless of the actual length ofpkg
. (#991, @salim-b)arg_match0()
is a faster version ofarg_match()
for use when performance is at a premium (#997, @krlmlr).
rlang 0.4.5
CRAN release: 2020-03-01
set_names()
,is_formula()
, andnames2()
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 basematch.arg
(#914, @AliciaSchep)
rlang 0.4.3
CRAN release: 2020-01-24
-
You can now use glue syntax to unquote on the LHS of
:=
. This syntax is automatically available in all functions taking dots withlist2()
andenquos()
, 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: 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()
andabort()
now check that eitherclass
ormessage
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 asabort()
to save unhandled errors tolast_error()
.Parsable constants like
NaN
andNA_integer_
are now deparsed byexpr_deparse()
in their parsable form (#890).Infix operators now stick to their LHS when deparsed by
expr_deparse()
(#890).
rlang 0.4.2
CRAN release: 2019-11-23
-
New
cnd_header()
,cnd_body()
andcnd_footer()
generics. These are automatically called byconditionMessage.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 conventionallocal_
prefix. For instance,scoped_bindings()
is nowlocal_bindings()
. Thescoped_
functions will be deprecated in the next significant version of rlang (0.5.0).The
.subclass
argument ofabort()
,warn()
andinform()
has been renamed toclass
. 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.
rlang 0.4.1
CRAN release: 2019-10-24
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 namedx
are prefixed with a red cross, elements namedi
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 fromlast_error()
.env_clone()
no longer recreates active bindings and is now just an alias forenv2list(as.list(env))
. Unlikeas.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 byrlang::last_trace()
) now includes the backtraces of the parent errors.cnd_signal()
has improved support for rlang errors created witherror_cnd()
. It now records a backtrace if there isn’t one already, and saves the error so it can be inspected withrlang::last_error()
.rlang errors are no longer formatted and saved through
conditionMessage()
. This makes it easier to use aconditionMessage()
method in subclasses created withabort()
, which is useful to delay expensive generation of error messages until display time.abort()
can now be called without error message. This is useful whenconditionMessage()
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 asstop(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 wheny
is of same length asx
(@rcannood, #806).Empty named lists are now deparsed more explicitly as
"<named list>"
.Fixed
chr()
bug causing it to return invisibly.
rlang 0.4.0
CRAN release: 2019-06-25
Tidy evaluation
Interpolate function inputs with the curly-curly operator
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))
}
More robust .env
pronoun
Another 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 functions and features
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 singleTRUE
orFALSE
. Likeis_string()
, it returnsFALSE
when the input is missing. This is useful for type-checking function arguments (#695).is_string()
gains astring
argument.is_string(x, "foo")
is a shortcut foris_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()
, andsignal()
. The vector is collapsed to a single string with a"\n"
newline separating each element of the input vector (#744).maybe_missing()
gains adefault
argument.New functions for weak references:
new_weakref()
,weakref_key()
,weakref_value()
, andis_weakref()
(@wch, #787).
Performance
The performance of
exec()
has been improved. It is now on the same order of performance asdo.call()
, though slightly slower.-
call2()
now uses the newpairlist2()
function internally. This considerably improves its performance. This also means it now preserves empty arguments:call2("fn", 1, , foo = ) #> fn(1, , foo = )
Bugfixes and small improvements
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 theerror
field ofrlang::last_error()
.ns_env()
andns_env_name()
(experimental functions) now support functions and environments consisently. They also require an argument from now on.is_interactive()
is aware of theTESTTHAT
environment variable and returnsFALSE
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).
Lifecycle
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()
andprepend()
(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 becausewith_handlers()
treats handlers as exiting by default.The vector constructors like
lgl()
ornew_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 likena_lgl
.as_logical()
,as_integer()
, etc have been soft-deprecated in favour ofvctrs::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()
, andcoerce_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.
rlang 0.3.2
CRAN release: 2019-03-21
Fixed protection issue reported by rchk.
The experimental option
rlang__backtrace_on_error
is no longer experimental and has been renamed torlang_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 leveloptions(error = rlang::entrace)
handling.
rlang 0.3.1
CRAN release: 2019-01-08
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.
Backtrace fixes
-
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 aclasses
argument to promote any kind of condition to an rlang error.New
last_trace()
shortcut to print the backtrace stored in thelast_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 aclasses
argument to specify which classes of condition to catch. It returnsNULL
if the expected condition could not be caught (#696).
as_label()
and as_name()
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.
Minor fixes and features
New
is_interactive()
function. It serves the same purpose asbase::interactive()
but also checks if knitr is in progress and provides an escape hatch. Usewith_interactive()
andscoped_interactive()
to override the return value ofis_interactive()
. This is useful in unit tests or to manually turn on interactive features in RMarkdown outputscalling()
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 tostructure()
.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. ReturnsNULL
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
ande2
) and purrr-style (.x
and.y
) arguments with binary primitives.exec()
takes.fn
as first argument instead off
, 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.
rlang 0.3.0
CRAN release: 2018-10-22
Breaking changes
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()
andquo_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 useas_string()
rather thanquo_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 toquos(x, y)
.-
The sentinel for removing arguments in
call_modify()
has been changed fromNULL
tozap()
. This breaking change is motivated by the ambiguity ofNULL
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.
Summary
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 withabort()
invite users to callrlang::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 withtrace_back()
) are printed in a simplified form by default that removes implementation details from the backtrace. To see the full backtrace, callsummary(rlang::last_error())
.abort()
also gains aparent
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 withbase::tryCatch()
orrlang::with_handlers()
and rethrow them with a high-level message. Callabort()
with the intercepted error as theparent
argument. When the user printsrlang::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 withinwith_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 thatvar
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 callsas.list()
on S3 objects andas(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
.
Conditions and errors
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 byabort()
(see below).abort()
gains aparent
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 withrlang::last_error()
. The error prints with a simplified backtrace. Callsummary(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 theabort()
,warn()
andinform()
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 functionRf_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()
andinform()
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 totryCatch()
). It also supports the formula shortcut for lambda functions (as in purrr).with_handlers()
now produces a cleaner stack trace.
Tidy dots
-
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 withlist2()
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:- Any other objects like functions or environments, but also language objects like formula, symbols, or quosures.
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()
andenquos()
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()
andenquos()
now support.ignore_empty = "all"
with named arguments as well (#414).dots_list()
gains a.preserve_empty
argument. WhenTRUE
, empty arguments are stored as missing arguments (see?missing_arg
).dots_list()
,enexprs()
andenquos()
gain a.check_assign
argument. WhenTRUE
, 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 evaluatesfoo
(#580).
Tidy eval
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"())
andexpr((!!"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 roundtripparse_expr(expr_deparse(x))
is not lossy.new_data_mask()
now throws an error whenbottom
is not a child oftop
(#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()
andas_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.
Environments
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()
andcurrent_fn()
functions to retrieve the current environment or the function being evaluated. They are equivalent tobase::environment()
andbase::sys.function()
called without argument.env_get()
andenv_get_list()
gain adefault
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 companionenv_label()
is likeenv_name()
but returns the memory address for anonymous environments.env_parents()
now returns a named list. The names are taken withenv_name()
.env_parents()
andenv_tail()
now stop at the global environment by default. This can be changed with thelast
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()
andenv_binding_are_lazy()
detect the kind of bindings in an environment.env_binding_lock()
andenv_binding_unlock()
allows to lock and unlock multiple bindings. The predicateenv_binding_are_locked()
tests if bindings are locked.env_lock()
andenv_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 tois_attached()
. It now supports environments in addition to search names.env_bind_lazy()
andenv_bind_active()
now support quosures.env_bind_exprs()
andenv_bind_fns()
are soft-deprecated and renamed toenv_bind_lazy()
andenv_bind_active()
for clarity and consistency.-
env_bind()
,env_bind_exprs()
, andenv_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 andenv_bind(env, foo = zap())
removes thefoo
binding.The
inherit
argument ofenv_get()
andenv_get_list()
has changed position. It now comes afterdefault
.scoped_bindings()
andwith_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()
callsget_env()
on its argument, making it easier to see the environment of closures and quosures (#567).env_get()
now supports retrieving missing arguments wheninherit
isFALSE
.
Calls
is_call()
now accepts multiple namespaces. For instanceis_call(x, "list", ns = c("", "base"))
will match ifx
islist()
or if it’sbase::list()
:call_modify()
has better support for...
and now treats it like a named argument.call_modify(call, ... = )
adds...
to the call andcall_modify(call, ... = NULL)
removes it.call_modify()
now preserves empty arguments. It is no longer necessary to usemissing_arg()
to add a missing argument to a call. This is possible thanks to the new.preserve_empty
option ofdots_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 ascall_modify()
now correctly check that their input is the right type (#187).
Other improvements and fixes
New function
zap()
returns a sentinel that instructs functions likeenv_bind()
orcall_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 toinvoke()
(#536).invoke()
has been soft-deprecated.Lambda functions created from formulas with
as_function()
are now classed. Useis_lambda()
to check a function was created with the formula shorthand.is_integerish()
now supports large double values (#578).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 instancefn_body(function(x) do())
returnsquote({ do() })
.is_string()
now returnsFALSE
forNA_character_
.The vector predicates have been rewritten in C for performance.
The
finite
argument ofis_integerish()
is nowNULL
by default. Missing values are now considered as non-finite for consistency withbase::is.finite()
.is_bare_integerish()
andis_scalar_integerish()
gain afinite
argument for consistency withis_integerish()
.flatten_if()
andsquash_if()
now handle primitive functions likebase::is.list()
as predicates.is_symbol()
now accepts a character vector of names to mach the symbol against.parse_exprs()
andparse_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 thequosures
class to its output.
Lifecycle
Soft-deprecated functions and arguments
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:
- rlang has been attached with a
library()
call. - The deprecated function has been called from the global environment.
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.
tidyeval
.data[[foo]]
is now an unquote operator. This guarantees thatfoo
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 thatgroup_by(df, .data[["name"]])
andgroup_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 (viapillar::type_sum()
if available), prevents multi-line names, and ensuresname
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()
andenquos()
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 withas.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()
andlength()
methods for data pronouns are deprecated. It is no longer valid to writenames(.data)
orlength(.data)
.Using
as.character()
on quosures is soft-deprecated (#523).
Miscellaneous
Using
get_env()
without supplying an environment is now soft-deprecated. Please usecurrent_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 equivalentrep_along()
orrep_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()
andenv_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
Deprecated functions and arguments issue a warning inconditionally, but only once per session.
-
Calling
UQ()
andUQS()
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()
andUQS()
can still be used for now. The
call
argument ofabort()
and condition constructors is now deprecated in favour of storing full backtraces.The
.standardise
argument ofcall_modify()
is deprecated. Please usecall_standardise()
beforehand.The
sentinel
argument ofenv_tail()
has been deprecated and renamed tolast
.
Defunct functions and arguments
Defunct functions and arguments throw an error when used.
as_dictionary()
is now defunct.The experimental function
rst_muffle()
is now defunct. Please usecnd_muffle()
instead. Unlike its predecessor,cnd_muffle()
is not generic. It is marked as a calling handler and thus can be passed directly towith_handlers()
to muffle specific conditions (such as specific subclasses of warnings).cnd_inform()
,cnd_warn()
andcnd_abort()
are retired and defunct. The oldcnd_message()
,cnd_warning()
,cnd_error()
andnew_cnd()
constructors deprecated in rlang 0.2.0 are now defunct.Modifying a condition with
cnd_signal()
is defunct. In addition, creating a condition withcnd_signal()
is soft-deprecated, please use the new function [signal()] instead.inplace()
has been renamed tocalling()
to follow base R terminology more closely.
Functions and arguments in the questioning stage
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()
andmodify()
are in the questioning stage, as well asas_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.
rlang 0.2.2
CRAN release: 2018-08-16
This is a maintenance release that fixes several garbage collection protection issues.
rlang 0.2.1
CRAN release: 2018-05-30
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.
rlang 0.2.0
CRAN release: 2018-02-20
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 unquotesa
rather than the wholea > b
expression.enquo()
works in magrittr pipes:mtcars %>% select(!!enquo(var))
.enquos()
is a variant ofquos()
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.
Tidy evaluation
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 makesenexpr()
andenquo()
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 unquotex
.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 than1:2
); unquoted S3 objects are displayed usingpillar::type_sum()
if available.-
New
enquos()
function to capture arguments. It treats...
the same way asquos()
but can also capture named arguments just likeenquo()
, i.e. one level up. By comparisonquos(arg)
only captures the namearg
rather than the expression supplied to thearg
argument.In addition,
enexprs()
is likeenquos()
but likeexprs()
it returns bare expressions. Andensyms()
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 toquo_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 ofenexpr()
that expects a symbol or a string and always returns a symbol. If a complex expression is supplied it fails with an error.exprs()
andquos()
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 notdots_list(nested_call(!!! x))
(#217).Functions taking dots with
list2()
ordots_list()
now support splicing ofNULL
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 tolapply()
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()
andUQS()
. 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()
, andquo_set_env()
. Compared toget_expr()
etc, these accessors only work on quosures and are slightly more efficient.quo_is_symbol()
andquo_is_call()
now take the same set of arguments asis_symbol()
andis_call()
.enquo()
andenexpr()
now deal with default values correctly (#201).Splicing a list no longer mutates it (#280).
Conditions
The new functions
cnd_warn()
andcnd_inform()
transform conditions to warnings or messages before signalling them.cnd_signal()
now returns invisibly.cnd_signal()
andcnd_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()
andabort()
now accept a call depth ascall
arguments. This allows plucking a call from further up the call stack (#30).New helper
catch_cnd()
. This is a small wrapper aroundtryCatch()
that captures and returns any signalled condition. It returnsNULL
if none was signalled.cnd_abort()
now adds the correct S3 classes for error conditions. This fixes error catching, for instance bytestthat::expect_error()
.
Environments
env_get_list()
retrieves muliple bindings from an environment into a named list.with_bindings()
andscoped_bindings()
establish temporary bindings in an environment.is_namespace()
is a snake case wrapper aroundisNamespace()
.
Various features
New functions
inherits_any()
,inherits_all()
, andinherits_only()
. They allow testing for inheritance from multiple classes. The_any
variant is equivalent tobase::inherits()
but is more explicit about its behaviour.inherits_all()
checks that all classes are present in order andinherits_only()
checks that the class vectors are identical.New
fn_fmls<-
andfn_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()
andcall_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 aname
argument to check that that the symbol name matches a string (#287).New
rlang_box
class. Its purpose is similar to theAsIs
class frombase::I()
, i.e. it protects a value temporarily. However it does so by wrapping the value in a scalar list. Usenew_box()
to create a boxed value,is_box()
to test for a boxed value, andunbox()
to unbox it.new_box()
andis_box()
accept optional subclass.The vector constructors such as
new_integer()
,new_double_along()
etc gain anames
argument. In the case of the_along
family it defaults to the names of the input vector.
Bugfixes
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 supportsNULL
and objects of type pairlist (#397).Fixed a performance bug in
set_names()
that caused a full copy of the vector names (@jimhester, #366).
API changes
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 tocall2()
. -
new_language()
has ben renamed tonew_call()
. -
is_lang()
has been renamed tois_call()
. We haven’t replaced theis_unary_lang()
andis_binary_lang()
because they are redundant with then
argument ofis_call()
. - All call accessors such as
lang_fn()
,lang_name()
,lang_args()
etc are soft-deprecated and renamed withcall_
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()
andnew_data_mask()
replaceas_overscope()
andnew_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.
Breaking changes
!!
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 unquotex > y
rather than justx
.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 thanUQE()
. 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()
andas_quosureish()
are deprecated. These functions assumed that quosures are formulas but that is only an implementation detail.new_cnd()
is nowcnd()
for consistency with other constructors. Also,cnd_error()
,cnd_warning()
andcnd_message()
are nowerror_cnd()
,warning_cnd()
andmessage_cnd()
to follow our naming scheme according to which the type of output is a suffix rather than a prefix.is_node()
now returnsTRUE
for calls as well andis_pairlist()
does not returnTRUE
forNULL
objects. Useis_node_list()
to determine whether an object either of typepairlist
orNULL
. 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.
Upcoming breaking changes
Calling the functional forms of unquote operators with the rlang namespace qualifier is soft-deprecated.
UQ()
andUQS()
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()
andUQS()
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 deprecateUQ()
andUQS()
in the future. In any case we recommend using the new functional forms.parse_quosure()
andparse_quosures()
are soft-deprecated in favour ofparse_quo()
andparse_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()
andf_env()
on quosures is soft-deprecated. The fact that quosures are formulas is an implementation detail that might change in the future. Please usequo_get_expr()
andquo_get_env()
instead.quo_expr()
is soft-deprecated in favour ofquo_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 tocall
, all these functions are soft-deprecated:lang()
,is_lang()
,lang_fn()
,lang_name()
,lang_args()
.In addition,
lang_head()
andlang_tail()
are soft-deprecated without replacement because these are low level accessors that are rarely needed. as_overscope()
is soft-deprecated in favour ofas_data_mask()
.The node setters were renamed from
mut_node_
prefix tonode_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 withdots_list()
.lgl_len()
,int_len()
etc have been soft-deprecated and renamed withnew_
prefix, e.g.new_logical()
andnew_integer()
. This is for consistency with other non-variadic object constructors.ll()
is now an alias tolist2()
. This is consistent with the newcall2()
constructor for calls.list2()
andcall2()
are versions oflist()
andcall()
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!!!
.
rlang 0.1.6
CRAN release: 2017-12-21
This is a maintenance release in anticipation of a forthcoming change to R’s C API (use
MARK_NOT_MUTABLE()
instead ofSET_NAMED()
).New function
is_reference()
to check whether two objects are one and the same.
rlang 0.1.4
CRAN release: 2017-11-05
-
eval_tidy()
no longer maps over lists but returns them literally. This behaviour is an overlook from past refactorings and was never documented.
rlang 0.1.2
CRAN release: 2017-08-09
This hotfix release makes rlang compatible with the R 3.1 branch.
rlang 0.1.1
CRAN release: 2017-05-18
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.
New functions:
The
new_environment()
constructor creates a child of the empty environment and takes an optional named list of data to populate it. Compared toenv()
andchild_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.
UI improvements:
env_child()
’s first argument is now.parent
instead ofparent
.mut_
setters likemut_attrs()
and environment helpers likeenv_bind()
andenv_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 returnsTRUE
forNULL
. We addedis_node()
to test for actual pairlist nodes. In other words,is_pairlist()
tests for the data structure whileis_node()
tests for the type.
Bugfixes:
env()
andenv_child()
can now get arguments whose names start with.
. Prior to this fix, these arguments were partial-matching onenv_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).