Say that instead of writing
sort(tapply(CPS$C == "S", CPS$M, sum, na.rm=TRUE))
I write
sort(tapply(CPS$C == "S", CPS$M, sum, rm.na=TRUE))
It seems that r-studio will happily run the function, ignoring the crucial parameter na.rm
That it ignores na.rm is expected (I did suply the function with the wrong parameter name). What I find surprising is that it runs at all.
Is there any way to convince R/R-studio to throw some sort of error, showing me that I made a typo, instead of running the function?
There is no "strict" mode, especially for functions that use ellipses to pass parameters through to other functions. Here sum
doesn't care about parameter names. For example
sum(1:4, whatever=4)
sum(1:4, 4)
run just fine and both return the same value. Rather than using such functions, you could write your own wrapper functions that more aggressively check parameter values. Here's a "safe" version of sum
safe_sum <- function(...) {
cx <- match.call()
cn <- names(cx)[-1]
if (!is.null(cn)) {
bad_names <- cn[cn!="" & cn!="na.rm"]
if(length(bad_names)) {
stop(paste("unexpected named parameter:", paste(bad_names, collapse=", ")))
}
}
cx[[1]] <- quote(sum)
eval(cx)
}
safe_sum(1:5, rm.na=TRUE)
# Error in safe_sum(1:5, rm.na = TRUE) : unexpected named parameter: rm.na
Which you can use with tapply
set.seed(10)
CPS <- data.frame(
C = sample(c("S","T"), 50, replace=TRUE),
M = sample(LETTERS[1:4], 50, replace=TRUE)
)
sort(tapply(CPS$C == "S", CPS$M, safe_sum , na.rm=TRUE))
# D A B C
# 3 5 8 9
sort(tapply(CPS$C == "S", CPS$M, safe_sum , rm.na=TRUE))
# Error in FUN(X[[i]], ...) : unexpected named parameter: rm.na
If you wanted to do this with other functions, you could create a factory to check all parameter names. Here's such a function
check_match_names <- function(fun) {
args <- formalArgs(args(sum))
args <- args[args!="..."]
function(...) {
cx <- match.call()
cn <- names(cx)[-1]
if (!is.null(cn)) {
bad_names <- cn[cn!="" & !(cn %in% args)]
if(length(bad_names)) {
stop(paste("unexpected named parameter:", paste(bad_names, collapse=", ")))
}
}
cx[[1]] <- fun
eval.parent(cx)
}
}
And then you would create your function with
safe_sum <- check_match_names(sum)
You can also use the package {ellipsis} to make a safe_sum
function :
safe_sum <- function(..., na.rm = FALSE) {
ellipsis::check_dots_unnamed()
sum(..., na.rm)
}
CPS<- data.frame(C = NA ,M = "A")
sort(tapply(CPS$C == "S", CPS$M, safe_sum, rm.na=TRUE))
#> Error: 1 components of `...` had unexpected names.
#>
#> We detected these problematic arguments:
#> * `rm.na`
#>
#> Did you misspecify an argument?
Created on 2020-09-28 by the reprex package (v0.3.0)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With