Skip to content

Commit

Permalink
Added a function, modify_in_place(), that attempts to modify the argu…
Browse files Browse the repository at this point in the history
…ment of its caller in place; bumped the released version.
  • Loading branch information
krivit committed Nov 18, 2024
1 parent 4a5190e commit 70093bf
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 3 deletions.
6 changes: 3 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: statnet.common
Version: 4.10.0-447
Date: 2024-09-23
Version: 4.11.0-453
Date: 2024-11-18
Title: Common R Scripts and Utilities Used by the Statnet Project Software
Authors@R: c(
person(c("Pavel", "N."), "Krivitsky", role=c("aut","cre"), email="[email protected]", comment=c(ORCID="0000-0002-9101-3362", affiliation="University of New South Wales")),
Expand All @@ -13,7 +13,7 @@ BugReports: https://github.com/statnet/statnet.common/issues
License: GPL-3 + file LICENSE
URL: https://statnet.org
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.2
RoxygenNote: 7.3.2.9000
Encoding: UTF-8
Suggests: covr,
rlang (>= 1.1.1),
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export(lweighted.cov)
export(lweighted.mean)
export(lweighted.var)
export(message_print)
export(modify_in_place)
export(nonsimp.update.formula)
export(nonsimp_update.formula)
export(once)
Expand Down
65 changes: 65 additions & 0 deletions R/misc.utilities.R
Original file line number Diff line number Diff line change
Expand Up @@ -926,3 +926,68 @@ unused_dots_warning <- function(e){
rlang::warn(sprintf("Argument(s) %s were not recognized or used. Did you mistype an argument name?",
paste.and(sQuote(v))))
}

#' Modify the argument in the calling environment of the calling function
#'
#' This is a helper function that enables a function to modify its argument in place, emulating behavior of \CRANpkg{R6} classes and methods in the \CRANpkg{network}. It should typically be the last line of the calling function.
#'
#' This function determines whether the argument can be assigned to by actually attempting to do so. If this results in an error, for example, because the argument is anonymous, the error is silently ignored.
#'
#' It can be called multiple times by the same function to modify multiple arguments. It uses the [on.exit()] mechanism, adding to the list. Thus, if some other function calls `on.exit(..., add = FALSE)` (the default) afterwards, `modify_in_place()` will fail silently.
#'
#' @param x the argument (not its name!) to be modified
#' @param value the value to assign (defaulting to the current value of `x`)
#'
#' @return `value`, invisibly, while attempting to modify `x` in place
#'
#' @examples
#' ## A function that increments its argument in place:
#' inc <- function(x){
#' modify_in_place(x, x+1)
#' }
#'
#' y <- 1
#' z <- 1
#'
#' stopifnot(inc(z) == 2)
#' stopifnot(z == 2)
#' stopifnot(inc(y) == 2)
#' stopifnot(y == 2)
#' stopifnot(inc(z) == 3)
#' stopifnot(z == 3)
#'
#' stopifnot(inc(identity(z)) == 4)
#' stopifnot(z == 3) # Not updated!
#'
#' ## Modify an argument that's been updated in place:
#' inc2 <- function(y){
#' y <- y + 1
#' modify_in_place(y)
#' }
#'
#' z
#' stopifnot(inc2(z) == 4)
#' stopifnot(z == 4)
#'
#' ## Decrement the first argument, increment the second:
#' incdec <- function(x,y){
#' modify_in_place(x, x-1)
#' modify_in_place(y, y+1)
#' }
#'
#' c(y,z)
#' incdec(y,z)
#' stopifnot(all(c(y,z) == c(1,5)))
#' @export
modify_in_place <- function(x, value = x){
xn <- substitute(x) # Grab the name of the argument to be updated.
xnn <- match.call(sys.function(-1), sys.call(-1))[[xn]] # Grab the expression that was passed into its argument.

eval.parent(on.exit( # As the calling function exits...
tryCatch( # try to...
eval.parent(call("<-", xnn, value), n = 2), # Assign `value` to whatever `xnn` stands for in the caller's calling environment.
error = identity # and do nothing if it fails.
), add = TRUE))

invisible(value) # Return invisibly.
}
63 changes: 63 additions & 0 deletions man/modify_in_place.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 70093bf

Please sign in to comment.