bokov
bokov

Reputation: 3534

Semi-automating argument validation for R functions

I would like the end-user functions in my R package (S3 style) to validate their arguments and give the user informative errors or warnings when a particular validity check fails.

The obvious (but tedious and unmaintainable) way to do this would be:

foo<-function(aa,bb,cc,dd){
  if(length(aa)!=1) stop("The argument 'aa' must have a single value");
  if(!is.numeric(aa)) stop("The argument 'aa' must be numeric");
  if(!is.character(bb)) stop("The argument 'bb' must be a character");
  if(length(bb)>=4||length(bb)<=2) stop("The argument 'bb' must be a vector with a length between 2 and 4");
  if(!is.recursive(cc)) stop("The argument 'cc' must be a list-like object");
  if(!is.integer(dd)) stop("The argument 'dd' must contain only integers");
  if(any(dd<aa)) stop("All values in the argument 'dd' must be greater than the value of argument 'aa'");
  ## ...and so on
}

I'm assuming that I'm by far not the first one to do this. So, can anybody suggest a package that automates all or part of such validation tasks? Or, failing that, some concise, generic idioms that will limit the ugliness to as few lines as possible within each function?

Thanks.

Upvotes: 4

Views: 354

Answers (2)

Ferdinand.kraft
Ferdinand.kraft

Reputation: 12819

You can write a helper function like this (rudimentary example):

validate <- function(x, ...){
    for(s in c(...)) switch(s,
        lengthone = if(length(x)!=1) stop("argument has length != 1."),
        numeric = if(!all(is.numeric(x))) stop("non-numeric arguments."),
        positive = if(any(x <= 0)) stop("non-positive arguments."),
        nonmissing = if(any(is.na(x))) stop("Missing values in arguments.")
    )
}

Results:

> validate(1, "numeric", "positive")
> validate(0, "numeric", "positive")
Error in validate(0, "numeric", "positive") : non-positive arguments.

Upvotes: 1

Dason
Dason

Reputation: 61933

stopifnot might be similar to what you're looking for. The error messages won't be quite as nice though

foo <- function(x){
    stopifnot(length(x) == 1, is.numeric(x))
    return(x)
}

which gives

> foo(c(1,3))
Error: length(x) == 1 is not TRUE
> foo("a")
Error: is.numeric(x) is not TRUE
> foo(3)
[1] 3

Upvotes: 5

Related Questions