4

I'm looking for a general practice how to check a parameter was defined in a function. I came up with these three ideas. Which one is the proper way of doing it?

Unfortunately, the third one is not working. substitute() is working differently in a function and I couldn't figure it out how to use it properly.

file.names <- list(
                   cov.value <- "cov.rds",
                   plot.name <- "plot.pdf"
)

test1 <- function(file.names){
  is.save <- !missing(file.names)
}

test2 <- function(file.names = NULL) {
  is.save <- !is.null(file.names)
}

test3 <- function(file.names = NULL) {
  is.save <- exists(as.character(substitute(file.names)))
}
microbe
  • 2,139
  • 3
  • 14
  • 17
  • 1
    I've seen both of the first two used in lots of places. I wouldn't recommend your third attempt. – joran May 02 '12 at 16:02
  • You might want to check out the answers to [this question](http://stackoverflow.com/q/9877271/1281189). I'm partial to [this answer](http://stackoverflow.com/a/9883471/1281189). – BenBarnes May 02 '12 at 16:37
  • @BenBarnes, thank for the link. The answer in the link is expended this question to test if a parameter is defined in ... argument. – microbe May 02 '12 at 17:55
  • @microbe, Thanks for looking at the links. `match.call()` will let you know if any arguments are defined (both formal arguments - in your example `file.names` - as well as ones supplied to `...`). – BenBarnes May 02 '12 at 18:12

2 Answers2

3

I personally think the second approach with a default value is MUCH easier to use & understand. (And the third approach is just really bad)

...especially when you are writing a wrapper function that needs to pass an argument to it. How to pass a "missing"-value is not obvious!

wraptest1 <- function(n) {
    file.names <- if (n > 0) sample(LETTERS, n) 
      else alist(a=)[[1]] # Hacky way of assigning 'missing'-value
    print(test1(file.names))
}
wraptest1(2) # TRUE
wraptest1(0) # FALSE

wraptest2 <- function(n) {
    file.names <- if (n > 0) sample(LETTERS, n) 
      else NULL # Much easier to read & understand
    print(test2(file.names))
}
wraptest2(2) # TRUE
wraptest2(0) # FALSE

[granted, there are other ways to work around passing the missing value, but the point is that using a default value is much easier...]

Some default values to consider are NULL, NA, numeric(0), ''

Tommy
  • 39,997
  • 12
  • 90
  • 85
2

It's generally a good idea to look at code from experienced coders---and R itself has plenty of examples in the R sources.

I have seen both your first and second example being used. The first one is pretty idiomatic; I personally still use the second more often by force of habit. The third one I find too obscure.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
  • Thanks for commenting. I guess the second is more traditional as you have a habit using it. :) I'll try to stick to the second and see if it fits me. – microbe May 02 '12 at 17:59