0

这是我在 R 中遇到过的最奇怪的事情。

是否有可能,某些参数名称(lazy在我的情况下)是特殊的/保留的,因此当涉及跨三个不同包的函数的调用堆栈时会导致意外行为:optionr::setAnywhereOptions()调用nestr::setNested()调用reactr::setShinyReactive()

考虑以下示例/情况(也在此GitHub 问题中描述)

改编自包中的这个单元测试optionr

require("devtools")
devtools::install_github("Rappster/conditionr")
devtools::install_github("Rappster/typr")
devtools::install_github("Rappster/nestr")
devtools::install_github("Rappster/reactr", ref = "bug-28")

devtools::install_github("Rappster/optionr")
require("optionr")

path <- file.path(tempdir(), "test")
create(path, description = getOption("devtools.desc"), check = FALSE,
  rstudio = TRUE)
setwd(path)

container <- initializeOptionContainer(overwrite = TRUE)  
setAnywhereOption(id = "x_1", value = TRUE, reactive = TRUE)
getAnywhereOption(id = "x_1")
setAnywhereOption(id = "x_2", 
  value = reactr::reactiveExpression(
    !getAnywhereOption(id = "x_1")
  ), 
  reactive = TRUE
)

getAnywhereOption(id = "x_1")
getAnywhereOption(id = "x_2")

请注意我为调试包含的状态消息:

DEBUG/push/before
[1] FALSE
DEBUG/lazy/before
Error in print(lazy) : argument is missing, with no default
DEBUG/is_lazy/before
[1] FALSE
DEBUG/lazy/after
[1] FALSE

出于某种原因,对于这个调用堆栈结构,函数reactr::setShinyReactive()似乎不再识别默认值,lazy而其他函数(例如 of push)似乎被识别得很好。

更准确地说,如果没有我的解决方法(见下文),R 在到达此代码部分时会抱怨。但是,如您所见,默认值定义,如果该函数被单独调用或从内部调用,它也可以正常工作nestr::setNested()

解决方法

当我将参数名称从更改lazyis_lazy(或仅包括is_lazy然后lazy <- is_lazy在正文中运行)时,一切正常(请参阅上面的调试输出)。

请参阅中的调试部分reactr::setShinyReactive()

疯狂猜测这里发生了什么

我首先想到的是,这一定词法作用域机制有关,因为“简单函数调用堆栈”不会出现这种行为。

第二个猜测是,也许S4机制在这里也造成了一些麻烦。也许也与这个问题有关?

4

1 回答 1

0

好吧,我不得不承认:那是一个非常愚蠢的错误。我无意中在对inside,的调用中有尾随nestr::setNested()optionr::setAnywhereOption()

这是一个更简单的插图:

定义

setGeneric(
  name = "setAnywhereOption",
  signature = "id",
  def = function(id, ...) standardGeneric("setAnywhereOption")      
)
setMethod(
  f = "setAnywhereOption", 
  signature = signature(id = "character"), 
#  definition = function(id, ...) setNested(id = id)
  ## --> works
#  definition = function(id, ...) setNested(id = id, ...)
  ## --> works
  definition = function(id, ...) setNested(id = id,)
  ## --> this leads to things get messed up with argument's default values
  ## --> so the trailing `,` was causing the problem!
)
setGeneric(
  name = "setNested",
  signature = "id",
  def = function(id, ...) standardGeneric("setNested")       
)
setMethod(
  f = "setNested", 
  signature = signature(id = "character"), 
  definition = function(id, ...) {

  if (FALSE) {  
    ## Omitted 
  } else {
    setShinyReactive(id = basename(id), ...)
  }

})
setShinyReactive <- function(
  id,
  lazy = FALSE,
  is_lazy = FALSE,
  push = FALSE,
  typed = FALSE,
  strict_set = c(0, 1, 2),
  ...
  ) {

  ###########
  ## DEBUG ##    
  ###########
  message("DEBUG/setShinyReactive/threedots")
  print(list(...))
  message("DEBUG/setShinyReactive/push")        
  print(push)    
  message("DEBUG/setShinyReactive/lazy")    
  try(print(lazy))
  ## --> strangely, R does not seem to like the name `lazy` 
  message("DEBUG/setShinyReactive/is_lazy")    
  print(is_lazy)
  ## --> this works
  lazy <- is_lazy
  message("DEBUG/setShinyReactive/lazy")    
  print(lazy)

  TRUE

}

申请

setAnywhereOption(id = "test")
# DEBUG/setShinyReactive/threedots
# list()
# DEBUG/setShinyReactive/push
# [1] FALSE
# DEBUG/setShinyReactive/lazy
# Error in print(lazy) : argument is missing, with no default
# DEBUG/setShinyReactive/is_lazy
# [1] FALSE
# DEBUG/setShinyReactive/lazy
# [1] FALSE
# [1] TRUE
setAnywhereOption(id = "test", push = TRUE)
setAnywhereOption(id = "test", lazy = TRUE)

解决方案

删除,方法定义中的尾随setAnywhereOption()

setMethod(
  f = "setAnywhereOption", 
  signature = signature(id = "character"), 
  definition = function(id, ...) setNested(id = id)
  ## --> works
#  definition = function(id, ...) setNested(id = id,)
  ## --> this leads to things get messed up with argument's default values
  ## --> so the trailing `,` was causing the problem!
)

setAnywhereOption(id = "test")
# DEBUG/setShinyReactive/threedots
# list()
# DEBUG/setShinyReactive/push
# [1] FALSE
# DEBUG/setShinyReactive/lazy
# [1] FALSE
# DEBUG/setShinyReactive/is_lazy
# [1] FALSE
# DEBUG/setShinyReactive/lazy
# [1] FALSE
# [1] TRUE

现在它工作得很好

于 2014-11-15T13:29:24.320 回答