This is not quite true. The value, even when invisible, is captured by
.Last.value, and
f <- function() invisible(5)
f()
.Last.value
[1] 5
I understand .Last.value will capture the function returns, but that only
happens in the top-level... I guess?
In the followings code, I think .Last.value does not capture the results
of f, h, k, l
g <- function() {
f(); h(); k(); l()
return()
}
g()
Maybe I caused confusion by mentioning `invisible` function. I guess it
should be a new function (let?s call it `delayed`). The function does not
have to be limited to ?printing?. For example, a digest key
a <- function(key, value) {
map$set(key, value)
return(*delayed*({
digest(value)
}))
}
Or an async evaluation of which the saved result might not be needed if
not assigned (detached), or the result will be ?joined? to the main process
a <- function(path) {
# async
f <- future::future({
# calculate, and then write to path
saveRDS(?, path)
})
return(*delayed*({
resolve(f) # wait till f to finish
readRDS(path)
}))
}
Although I could use wrappers such as formula, quosure, or environment to
achieve similar results, there are two major differences
1. There is an extra call to get the lazy-evaluated results (if I do want
to resolve it)
2. The returned objects have to contain sort of ?environment? component in
it. It can?t just be simple objects like vectors, matrices, lists, ?
(also you can't immediately garbage collect the enclosing environment)
From the implementation perspective, the `delayed` object is ready to be
garbage collected if not assigned immediately.
Best,
- D
This is not quite true. The value, even when invisible, is captured by
.Last.value, and
f <- function() invisible(5)
f()
.Last.value
[1] 5
Now that doesn't actually preclude what you're suggesting (just have to
wait for .Last.value to be populated by something else), but it does
complicate it to the extent that I'm not sure the benefit we'd get would be
worth it.
Also, in the case you're describing, you'd be pushing the computational
cost into printing, which, imo, is not where it should live. Printing a
values generally speaking, should just print things, imo.
That said, if you really wanted to do this, you could approach the
behavior you want, I believe (but again, I think this is a bad idea) by
returning a custom class that wraps formula (or, I imagine, tidyverse style
quosures) that reach back into the call frame you return them from, and
evaluating them only on demand.
Best,
~G
This idea is somewhere between `delayedAssign` and eager evaluation.
Maybe we could call it delayedInvisible()?
Best,
- Zhengjia