r-lib / memoise

Easy memoisation for R
https://memoise.r-lib.org
Other
317 stars 59 forks source link

on.exit statements in functions lead to unexpected behaviour #113

Open knthls opened 4 years ago

knthls commented 4 years ago

During debugging my Package I found that some functions need to be evaluated two times, before memoise returns the stored result on every subsequent call. I found that this is because on.exit statements change the hash value of the functions body, after being evaluated for the first time.

fun <- function() {
  on.exit({
    print("foo")
  })
  "bar"
}

print(digest(body(fun)))
fun()
print(digest(body(fun)))

I wonder if it is possible, that memoise takes care of this, admittedly rather special, case, maybe by using as.character(body(fun)), which isn't affected by the first evaluation.

I asked the same question in the digest package repo here: https://github.com/eddelbuettel/digest/issues/160, but I guess a workaround would rather be a matter for memoise.

hadley commented 4 years ago

Hmmmmm, this is a weird one. I'm not sure what memorise can do about it:

fun1 <- function() {
  on.exit({
    print("foo")
  })
  "bar"
}
fun2 <- function() {
  on.exit({
    print("foo")
  })
  "bar"
}
fun1 <- utils::removeSource(fun1)
fun2 <- utils::removeSource(fun2)

digest::digest(fun1)
#> [1] "7d327b864fe565bb55818c8696763cc3"
digest::digest(fun2)
#> [1] "7d327b864fe565bb55818c8696763cc3"

fun1()
#> [1] "foo"
#> [1] "bar"
digest::digest(fun1)
#> [1] "85fc41ede4e5f9925cce34d75140d2fd"

waldo::compare(fun1, fun2)
#> ✓ No differences
waldo::compare(lobstr::sxp(fun1), lobstr::sxp(fun2))
#> `attr(x, 'addr')`: "0x7fd978febd28"
#> `attr(y, 'addr')`: "0x7fd988e5ca28"
#> 
#> `attr(x$_body, 'addr')`: "0x7fd978ff0818"
#> `attr(y$_body, 'addr')`: "0x7fd988e98810"
#> 
#> `attr(x$_env, 'length')`: 2
#> `attr(y$_env, 'length')`: 3

Created on 2020-09-02 by the reprex package (v0.3.0.9001)