作为my previous question on the usage of &&
and ||
in if
statements的后续行动,我想知道在我自己的软件包中用纯标量运算符替换&&
和||
是否有任何缺点。这些应该产生与它们的基本对应物完全相同的结果,除了它们在应用于长度> 1的参数时抛出错误消息。特别是,它们会短路。
`&&` <- function(x, y) {
if (!x[1]) {
stopifnot(length(x) == 1)
return(FALSE)
}
stopifnot(length(x) == 1)
if (!y[1]) {
stopifnot(length(y) == 1)
return(FALSE)
}
stopifnot(length(y) == 1)
TRUE
}
`||` <- function(x, y) {
if (x[1]) {
stopifnot(length(x) == 1)
return(TRUE)
}
stopifnot(length(x) == 1)
if (y[1]) {
stopifnot(length(y) == 1)
return(TRUE)
}
stopifnot(length(y) == 1)
FALSE
}
在包装中进行这些替换是否安全?或者可能会破坏某些东西? (除了实际依赖于矢量化行为的函数,显然......)
请注意,我不打算导出这些功能;它们仅供我内包装使用。
如果我理解正确,那么这些替换只会影响我自己的功能。它们不会影响我的包裹以外的任何东西,对吧?
答案 0 :(得分:1)
没有。您可能能够使计算机安全,但代码也需要对读者安全。有一天你会想和别人分享这个代码,或者你会在一段时间后自己回来,这种超载会让人感到困惑。到目前为止,最好使用新的函数名称。
此外,您需要非常小心处理您的函数如何处理NA
和NULL
值。您当前版本的行为与NA
的常规版本不同,可能与NULL
不同;我没有做全面检查。但我很惊讶地注意到,当其中一个输入为NULL
时,订单对标准R版本很重要。
编辑:NA
值的这个问题值得思考,可能还有另一个原因,就是不要只编写一个旨在取代&&
和||
的函数。对于流控制,您需要TRUE或FALSE,NA将抛出错误。那么TRUE && NA
会抛出错误吗?或者FALSE
?甚至是TRUE
?这可能取决于if(!is.na(x) && x)
或if(any(is.na(x)))
的常见事情可能为读者提供更多的灵活性和清晰度。
如果我要继续,我的偏好是将您的新版本视为all
和any
的标量版本并相应地命名,以便像scalar.all(a, b)
一样使用a && b
。或者,如果您从流量控制角度考虑它,可以添加一个参数来描述如何处理NA
值,flowcontrol.all(a, b, na=c("error", "TRUE", "FALSE")
。
顺便说一下,我赞赏你的努力。意识到这些问题并编写代码以保证它们的安全性似乎是一个好主意。然而,在考虑了这一点并尝试简要地编写我自己的版本之后,我觉得在你自己的软件包中,最好根据需要逐个进行。有时您会知道作为包编写器的一个或两个输入只能是标量,然后这个额外的代码是不必要的。
但是,这是scalar.all
函数的尝试。
scalar.all <- function(...) {
ns <- eval(substitute(alist(...)))
sofar <- TRUE
for(n in ns) {
x <- eval(n)
if (length(x) != 1L) {
stop(paste(list(n)), " is not a scalar with length 1")
}
if (is.na(x)) sofar <- NA
else if (!x) return(FALSE)
}
sofar
}