ropensci-books/drake

High-level guidance on how drake watches for changes

wlandau opened this issue · 2 comments

drake's dependency-watching behavior can be counterintuitive, even for seasoned users. Imported functions are an example. drake tracks the literal deparsed version of a function and ignores the closure (except for functions produced by Vectorize()). purrr::possibly() is an edge case where this approach falls short. reprex from @aedobbyn:

library(drake)

try_fun <- purrr::possibly(log,
                           otherwise = 0)

f <- function(x) {
  try_fun(x) + 1
}

plan <- drake_plan(
  out = f("a")
)

make(plan)
#> target out

try_fun <- purrr::possibly(sum,
                           otherwise = 1)

make(plan)
#> All targets are already up to date.

And then there are plans like this one (ref: ropensci/drake#1063) which could use more guidance about what is important to track.

All this deserves a subsection of the manual well before the chapter on triggers. Maybe the newly overhauled plans chapter is a good place. Could go well with the section on file_in() etc.

On second thought, let's make it an entire chapter. Static code analysis is one of the major features that separates drake from other pipeline toolkits. Explaining this will justify drake's existence in this competitive space, and understanding it opens up a lot of power and control for users. The information will replace caution.Rmd, which is going away, re #127.

On reflection, I think this is best handled in the existing chapter on triggers. I just added a bit of explanation next to the mention of imported functions.