In my neverending quest to break things, consider:
gbar<-function(x,y,x,a) x+2*y-4*a
Error: repeated formal argument 'x' on line 1
R
properly checks my defined function for illegal formals.
But if I manually foul things up:
ffoo<-function(x,y,a) x+2*y-4*a
formals(ffoo)<-c(x=7, formals(ffoo))
Then I'll only find out under certain circumstances that something is invalid.
ffoo(3,4,5,6)
will execute properly (although probably not giving me the answer I expected), as will ffoo(y=3,a=2)
; whereas ffoo(x=5,y=3,a=2)
will throw an error about ambiguous argument names.
So: is there any base-R
or advanced utility package with a function to do 'sanity' checking on the formals
of an existing function?
Edit:
If you simply want to check for duplicated arguments, you can do this:
any(duplicated(names(formals(ffoo))))
# [1] TRUE
As Hadley mentions in his second comment below, dput()
isn't guaranteed to give you a good/complete representation of a function, so there may be functions for which the approach described in my original answer (left in place below) fails.
Original answer:
As is hinted at in the C code pointed to by Andrie, this is apparently a check that R performs while parsing (not evaluating) a call to function()
. That's why you were able to circumvent the check with your call to formals<-
, and it's why the following (for example) also avoids getting checked. In both cases, the function is modified/created without parsing a call to function()
.
eval(call("function", formals(ffoo), body(ffoo)))
# function (x = 7, x, y, a)
# x + 2 * y - 4 * a
R's parsing machinery isn't typically exposed in user-visible R functions, so I'd guess there's no ready-made function R function to perform this check. You could, though, perform the exact same set of checks that R does when you source the expression or enter it at a at a command line by converting the function definition to its character representation and then attempting re-parse it yourself.
Here's the general idea:
parse(text = capture.output(dput(ffoo)))
# Error in parse(text = capture.output(dput(ffoo))) :
# repeated formal argument 'x' on line 1
To wrap the check up as a function do something like this:
isParseableFunction <- function(x) {
tryCatch(is.function(x) &
is.expression(parse(text = capture.output(dput(x)))),
error = function(e) FALSE)
}
isParseableFunction(data.frame)
# [1] TRUE
isParseableFunction(mean)
# [1] TRUE
isParseableFunction(ffoo)
# [1] FALSE
isParseableFunction(99)
# [1] FALSE
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