Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to check modified function formals

Tags:

r

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?

like image 934
Carl Witthoft Avatar asked Sep 30 '22 19:09

Carl Witthoft


1 Answers

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
like image 107
Josh O'Brien Avatar answered Oct 03 '22 02:10

Josh O'Brien