vctrs icon indicating copy to clipboard operation
vctrs copied to clipboard

Implement make_restore()?

Open krlmlr opened this issue 3 years ago • 4 comments

Should we make it easier to implement functions that call another function and then vec_restore() on the result?

x <- pillar::num(c(1, 2, 4), notation = "eng")
x
#> <pillar_num(eng)[3]>
#> [1] 1e0 2e0 4e0

# mean() keeps formatting
mean(x)
#> <pillar_num(eng)[1]>
#> [1] 2.33e0

# var() loses formatting
var(x)
#> [1] 2.333333

# Manual wrapper
var_ <- function(x, ...) {
  out <- var(x, ...)
  vctrs::vec_restore(out, x)
}
var_(x)
#> <pillar_num(eng)[1]>
#> [1] 2.33e0

# Easily create restoring wrappers?
make_restore <- function(fun) {
  force(fun)
  function(x, ...) {
    out <- fun(x, ...)
    vctrs::vec_restore(out, x)
  }
}

var_ <- make_restore(var)
sd_ <- make_restore(sd)

var_(x)
#> <pillar_num(eng)[1]>
#> [1] 2.33e0
sd_(x)
#> <pillar_num(eng)[1]>
#> [1] 1.53e0

Created on 2021-04-12 by the reprex package (v1.0.0)

krlmlr avatar Apr 12 '21 03:04 krlmlr

Note that it is undefined behaviour to call vec_restore() on something other than the result of vec_proxy().

The suggested operator would allow things like taking the var() of factors.

lionel- avatar Apr 12 '21 08:04 lionel-

Added vec_proxy() in https://github.com/r-lib/pillar/pull/316.

I'm seeing this for factors, var() already checks this:

# Easily create restoring wrappers?
make_restore <- function(fun) {
  force(fun)
  function(x, ...) {
    out <- fun(x, ...)
    vctrs::vec_restore(out, vctrs::vec_proxy(x))
  }
}

var_ <- make_restore(var)
sd_ <- make_restore(sd)

var_(factor(1:3))
#> Error in fun(x, ...): Calling var(x) on a factor x is defunct.
#>   Use something like 'all(duplicated(x)[-1L])' to test for a constant vector.

Created on 2021-04-18 by the reprex package (v1.0.0)

krlmlr avatar Apr 18 '21 03:04 krlmlr

ah yes that works out in this particular case because the proxy function of a factor is identity() and var() special-cases factors.

lionel- avatar Apr 19 '21 06:04 lionel-

This:

make_restore <- function(fun) {
  force(fun)
  function(x, ...) {
    out <- fun(x, ...)
    vctrs::vec_restore(out, vctrs::vec_proxy(x))
  }
}

Should be:

make_restore <- function(fun) {
  force(fun)
  function(x, ...) {
    out <- fun(vctrs::vec_proxy(x), ...)
    vctrs::vec_restore(out, x)
  }
}

lionel- avatar Apr 19 '21 06:04 lionel-

Proxy and restore are mostly internal functions at the moment.

lionel- avatar Sep 15 '22 09:09 lionel-