organize blocks of code in R with with() ?

[This article was first published on R – kata helion, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

In their “Object-Oriented Programming is Bad” video, Brian Will mentions a desired reserved word: use (timestamp) that could look something like this:

a = use x, y {
  ...
  return 3;
}

The variables you specify come from the enclosing scope and would be available as copies within a separate scope defined by the curly braces. basically an anonymous function with more intuitive (?) syntax. One benefit would be if you did want to reuse this code block later it’d be very easy to convert to a full fledged function and if it was one off code you could just leave it. You also get some scoping control and added readability (maybe?).

My first thought was that this is actually already easy to do in R with with():

x <- 1
y <- with(x, {
  x <- x * 2
  x + 1
})

print(paste(x, y))
# [1] "1 3"

is this pleasantly predictable behavior? not sure. the man page for with() warns:

For interactive use this is very effective and nice to read. For programming however, i.e., in one’s functions, more care is needed, and typically one should refrain from using with(), as, e.g., variables in data may accidentally override local variables, see the reference.

‘with’ help page Package base version 4.3.1 (R Core Team, 2023)

For Brian Will’s purposes these are actually desirable qualities I think. but note you have to pass with() an integer, data frame, or list. That’s not that cumbersome though, but does it spoil the simplicity?

x <- 1
z <- 2
y <- with(list(x, z), {
  x <- x * 2
  x + 1 + z
})

print(paste(x, z, y)
# [1] "1 2 5"

You can get the same effect with do.call, but the syntax isn’t as nice looking, because (1) the input comes after the expression and (2) you need to use an actual function– an expression doesn’t work. You also need to pass a list like with with():

x <- 1
y <- do.call(function(x) {
  x + 2
}, list(x))

# or

f1 <- function(x) { x + 2 }
y <- do.call('f1', list(x))

I think readability and analogy to a simple function call aren’t quite as good for do.call in this particular use case when compared to with(), but I’m not knocking do.call, it is generally great.

Is this worth it either with do.call or with()? Does this make things easier or harder to debug? Would it be better to just use local functions to organize code into blocks like this even if they are only used once? Is it confusing if those functions live in a separate file?

Library of Congress, Prints & Photographs Division, LC-DIG-ppmsc-01765 (digital file from original)
To leave a comment for the author, please follow the link and comment on their blog: R – kata helion.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)