tidyverse / purrr

A functional programming toolkit for R
https://purrr.tidyverse.org/
Other
1.28k stars 272 forks source link

`as_mapper.default()` is relatively slow #1088

Open mgirlich opened 1 year ago

mgirlich commented 1 year ago

Nearly half the time in this example is spend in as_mapper.default(). The issue i

x <- as.list(1:20)
x[21] <- list(NULL)

for (i in 1:10e3) {
  purrr::detect_index(x, is.null)
}

image

This leads to the curious situation that it is faster to manually wrap is.null() yourself in a function:

x <- as.list(1:20)
x[21] <- list(NULL)

bench::mark(
  wrapped = purrr::detect_index(x, function(x) is.null(x)),
  prim = purrr::detect_index(x, is.null)
)
#> # A tibble: 2 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 wrapped        61µs   66.1µs    13236.     446KB     16.6
#> 2 prim          129µs  145.4µs     6387.     232KB     14.6

Created on 2023-07-05 with reprex v2.0.2

hadley commented 1 year ago

Hard to see how to fix without breaking this test:

test_that("primitive functions are wrapped", {
  expect_identical(as_mapper(`-`)(.y = 10, .x = 5), -5)
  expect_identical(as_mapper(`c`)(1, 3, 5), c(1, 3, 5))
})

But maybe that's ok since we don't generally expect - to respect named arguments?