Testing function agruments in GNU R

June 28, 2013

(This article was first published on R snippets, and kindly contributed to R-bloggers)

Recently I have read a nice post on ensuring that proper arguments are passed to a function using GNU R class system. However, I often need a more lightweight solution to repetitive function argument testing.
The alternative idea is to test function arguments against a specified pattern given in a string. The pattern I use has the form:
([argument type][required argument length])+.
The allowed argument types are:
  b     logical
  i     integer
  d     double
  n     numeric
  c     complex
  s     character
  f     function
  l     list
  a     any type

and argument lengths are:
  ?     0 or 1
  *     0 or more
  +     1 or more
  n     exactly n
So for example pattern “n2f?s+” means that function requires three arguments: one numeric vector of length 2, a function (or nothing) and character vector of any positive length.
The function that performs checking of the arguments against the pattern is given here:
is.valid <- function(rule, …, empty.null = TRUE) {
    err <- function(type, position, required, found) {
        e <- FALSE
        attr(e, “type”) <- type
        attr(e, “position”) <- position
        attr(e, “required”) <- required
        attr(e, “found”) <- found
    stopifnot(require(stringr, quietly = T))
    arglist <- list()
    if (!(is.character(rule) ||
        (length(rule) == 1)) ||
        (nchar(rule) == 0)) {
        stop(“improper rule: rule must be a nonempty string”)
    type <- str_locate_all(rule, “[bidncsfla]”)[[1]]
    count <- invert_match(type)
    type <- str_sub(rule, type[,1], type[,2])
    count <- str_sub(rule, count[,1], count[,2])
    if (count[1] != “”) {
        stop(“improper rule: rule must start with type [bidncsfl]”)
    count <- count[-1]
    if (length(count) != length(type)) {
        stop(“improper rule: number of type and count specifiers must be equal”)
    for (i in seq_along(count)) {
        if ((!count[i] %in% c(“?”, “*”, “+”)) &&
            (regexpr(“^[1-9][0-9]*$”, count[i]) == 1)) {
                stop(paste(“improper rule: unrecognized count”,
    if (length(type) != length(arglist)) {
        stop(“improper rule: number of type specifiers must be equal to number of variables”)
    for (i in seq_along(count)) {
        if ((!count[i] %in% c(“?”, “*”, “+”)) &&
            (regexpr(“^[1-9][0-9]*$”, count[i]) == 1)) {
                stop(paste(“improper rule: unrecognized count”,
        if ((count[i] %in% c(“?”, “*”)) &&
            is.null(arglist[[i]]) &&
            empty.null) {
        if (!switch(type[i],
               b = is.logical(arglist[[i]]),
               i = is.integer(arglist[[i]]),
               d = is.double(arglist[[i]]),
               n = is.numeric(arglist[[i]]),
               c = is.complex(arglist[[i]]),
               s = is.character(arglist[[i]]),
               f = is.function(arglist[[i]]),
               l = is.list(arglist[[i]]),
               a = TRUE)) {
            return(err(“type”, i, type[i], typeof(arglist[[i]])))
        if (count[i] == “?”) {
            if (length(arglist[[i]]) > 1) {
                return(err(“count”, i, count[i],
        } else if (count[i] == “*”) {
            # nothing to do – always met
        } else if (count[i] == “+”) {
            if (length(arglist[[i]]) == 0) {
                return(err(“count”, i, count[i],
        } else {
            if (length(arglist[[i]]) != as.integer(count[i])) {
                return(err(“count”, i, as.integer(count[i]),


Its first argument is rule a pattern that arguments should meet. Next the arguments are passed. For example in the following calls:
          T, 1L, 1.0, 1, 1i, “1”, sin, list(1), raw(1)) # TRUE
          T, 1L, 1.0, 1, 1i, “1”, sin, list(1), raw(2)) # FALSE

          T, 1L, 1.0, 1, 1i, “1”, sin, 1, raw(1))       # FALSE

the first is returns TRUE and second and third return FALSE (in the first there an improper length of last argument and in the second improper variable type). In case when FALSE is returned it contains attributes with diagnostic information on validation error type.
Additionally the function has an optional parameter empty.null. It influences the way it handles variables of length 0 (which are allowed when “?” or “*” argument length constraint is used). If it is set to TRUE then NULL as an argument is accepted as valid. You can see this in action in the following code:
is.valid(“l?”NULL)                                    # TRUE
is.valid(“l?”, NULLempty.null = FALSE)                # FALSE
In summary is.valid function is a simple and compact way to check type and length of passed arguments and can be considered as an alternative to the approach proposed in the post I have mentioned above.

To leave a comment for the author, please follow the link and comment on their blog: R snippets.

R-bloggers.com offers daily e-mail updates about R news and tutorials on topics such as: Data science, Big Data, R jobs, visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...

If you got this far, why not subscribe for updates from the site? Choose your flavor: e-mail, twitter, RSS, or facebook...

Comments are closed.

Search R-bloggers


Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)