| withdots | R Documentation |
... if it does not have itAdds ... to a closure's args if it does not have it already.
withdots(f)
f |
A function. See Handling of primitives in case |
If f already has ... in its args, then it is returned with no
changes. Otherwise, ... is added to f's formals and then f is
returned. See Handling of primitives below.
If f has ... in its args, then f.
Otherwise, a closure: a tweaked version of f, whose only differences
are:
... has been appended to the end of its formals, and
any srcref attribute has been removed (see Why the
srcref attribute is removed below).
... is added to closuresThese are the steps that
withdots() takes only if f is a closure without ... in
its formals:
attributes(f) are temporarily saved and set aside.
If there is a srcref attribute among the set-aside
attributes(f), it is removed (see Why the srcref
attribute is removed below).
... is added to the formals of f using formals<-.
The remaining set-aside attributes are added back to f with
attributes<-.
f is returned.
If f is primitive and already has
... in its args (e.g., c(), rep(), max()), then it is
returned as is.
If f is primitive and does not have ... in its args,
then an error will be thrown. The user can bypass this error by processing
f with rlang::as_closure() before passing it to withdots().
However, keep in mind that the argument matching behavior of the
resulting closure may be different from what is expected, since
primitives may use nonstandard argument matching.
srcref attribute is removedMany
functions—including those created with function()—have a srcref
attribute. When a function is printed, print.function()
relies on this attribute by default to depict the function's
formals and body.
withdots() adds ... via formals<-, which expressly drops
attributes (see its documentation page). To prevent this
loss, withdots() sets attributes(f) aside at the beginning and
re-attaches them to f at the end. Normally, this would re-attach the
original f's srcref attribute to the new f, making it so
that the newly added ... would not be depicted when the new f
is printed. For this reason, the old srcref attribute is
dropped, and only the remaining attributes are re-attached to the new
f.
Observe what would happen during printing if all original
attributes(f) were naively added to the modified f:
# Create a function with no dots:
foo <- function(a = 1) {
# Helpful comment
a
}
# Give it important attributes that we can't afford to lose:
attr(foo, "important_attribute") <- "crucial information"
class(foo) <- "very_special_function"
# Print foo, which also prints its important attributes:
foo
#> function(a = 1) {
#> # Helpful comment
#> a
#> }
#> <environment: 0x571c620>
#> attr(,"important_attribute")
#> [1] "crucial information"
#> attr(,"class")
#> [1] "very_special_function"
# Save its attributes:
old_attributes <- attributes(foo)
# Add dots:
formals(foo)[["..."]] <- quote(expr = )
# See that the important attributes have been dropped:
foo
#> function (a = 1, ...)
#> {
#> a
#> }
#> <environment: 0x571c620>
# Add the attributes back:
attributes(foo) <- old_attributes
# Print it again, and we see that the attributes have returned.
# However, the ... disappears from the argument list.
foo
#> function(a = 1) {
#> # Helpful comment
#> a
#> }
#> <environment: 0x571c620>
#> attr(,"important_attribute")
#> [1] "crucial information"
#> attr(,"class")
#> [1] "very_special_function"
# We know the actual function definitely has dots, since it can handle
# extraneous arguments:
foo(1, 2, junk, "arguments", NULL)
#> [1] 1
# Remove the "srcref" attribute, and the function is printed accurately.
# Furthermore, its important attributes are intact:
attr(foo, "srcref") <- NULL
foo
#> function (a = 1, ...)
#> {
#> a
#> }
#> <environment: 0x571c620>
#> attr(,"important_attribute")
#> [1] "crucial information"
#> attr(,"class")
#> [1] "very_special_function"
# Success (although the comments in the body() of the function are lost)
# The base::match() function has no ... and can't handle extraneous arguments
if (FALSE) {
match("z", letters, cannot_handle_ = "junk arguments")
}
# But if we give it dots...
match_with_dots <- withdots(match)
# ...it can now handle extraneous arguments:
match_with_dots("z", letters, can_now_handle = "junk arguments")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.