Skip to contents

If any of the named expressions in ... are not the specified size, then the object attempts to be recycled to the size specified in the expression. Expressions are evaluated and variables are assigned into the environment specified by the .env argument. The checking of size and the recycling are from the vctrs package (using vctrs::vec_size and vctrs::vec_recycle) and thus stick to the vctrs recycling rules.

Usage

recycle_if_not(
  ...,
  .env = caller_env(),
  .class = NULL,
  .error_call = caller_env()
)

Arguments

...

any number of named R expressions, in the form of: name_of_obj_to_cast = size_to_cast_to

.env

the environment to use for the evaluation of the recycling expressions & the assignment of the recycled variables. Cannot be the global environment.

.class

class to assign to the error (passed to rlang::abort).

.error_call

the call environment to use for the error (passed to rlang::abort).

Examples

# Will not alter the global environment so most examples here are wrapped with local().
x <- 1
recycle_if_not(x = 1) |> try()
# => Error: Argument `call` cannot be the global environment.

local({
  x <- 1
  recycle_if_not(x = 3)
  x
})
#> [1] 1 1 1

local({
  x <- rep(1, 4)
  recycle_if_not(x = 1) |> try()
})
#> Error in eval(quote({ : Error in `recycle_if_not()`
#>  Can't recycle `x` (size 4) to size 1.
# => Error : Can't recycle `x` (size 4) to size 1.

local({
  x <- 1L
  y <- 2.3
  recycle_if_not(x = 3, y = 2)
  cat(x, y, sep = ", ")
})
#> 1, 1, 1, 2.3, 2.3

# beware when using other objects as the size argument, e.g.:
local({
  x <- 1L
  y <- c(1, 1, 1)
  recycle_if_not(x = y) |> try()
})
#> Error in eval(quote({ : Error in
#>  Size argument for `x` is not a scalar integerish value: object length `3` of
#>   class <numeric>.
# => Error : Size argument for `x` is not a scalar integerish value:
# object length `3` of class <numeric>.

# when using other objects, call vctrs::vec_size() on them first:
local({
  x <- 1L
  y <- c(1, 1, 1)
  recycle_if_not(x = vctrs::vec_size(y))
  x
})
#> [1] 1 1 1

# recycle_if_not works sequentially, so references to objects will
# be after they have been evaluated:
local({
  x <- y <- 1
  recycle_if_not(x = 3, y = vctrs::vec_size(x))
  cat(length(x), length(y), sep = ", ")
})
#> 3, 3

myfunc <- \(x) {
  recycle_if_not(x = 3)
  x
}
x <- 1L
myfunc(x) # x is recycled to length 3 within the function
#> [1] 1 1 1
x # x is still scalar outside the function
#> [1] 1

local({
  x <- 1
  y <- 2
  z <- 3
  recycle_if_not(x = 2, y = 3, z = 4)
  cat(x, y, z, sep = ", ")
})
#> 1, 1, 2, 2, 2, 3, 3, 3, 3

# the `.env` argument determines the expression and assignment environment:
local({
  x <- 1
  e <- new.env()
  e$x <- 1
  recycle_if_not(x = 3, .env = e)
  cat(length(e$x), length(x), sep = ", ")
})
#> 3, 1

# names (lhs) are checked to be in the `.env` environment,
# throwing an error if not found:
local({
  x <- 1
  e <- new.env()
  recycle_if_not(x = 3, .env = e) |> try()
})
#> Error in eval(quote({ : Error in `recycle_if_not()`
#>  Objects `x` are not found in the `.env` environment specified.
# Error: Objects `x` are not found in the `.env` environment specified.

# for expressions (rhs), the `.env` argument is preferentially chosen,
# but if not found then the normal R scoping rules apply:
local({
  x <- 3
  e <- new.env()
  e$z <- 1
  recycle_if_not(z = x, .env = e)
  cat(e$z)
})
#> 1 1 1