5
votes

We have a function that requires multiple arguments without default values for any of them. However, even if some of them are not specified, the function returns a value, if these parameters are only used to subset a matrix (and possibly other types). We are puzzled why this is the case - can anybody help?

Specifically, why does the following code not return an error, but sums over the entire matrix and ignores j:

foo <- function(mat, j){
  v <- sum(mat[,j])
  v
}

foo(mat = matrix(1:4,3,4))
3

3 Answers

4
votes

According to this blog, optional arguments without defaults are missing from the inside of the function. Testing for it returns TRUE.

foo <- function(mat, j){
   v <- sum(mat[,j]); print(missing(j))
   v
}
foo(mat = matrix(1:4,3,4))
[1] TRUE
[1] 30

Without knowing what the specifics were, I experimented with sum a bit and this is what it shows.

sum(matrix(1:4,3,4)[,NA])
[1] NA
sum(matrix(1:4,3,4)[,NULL])
[1] 0
sum(matrix(1:4,3,4)[,])
[1] 30

If we do not specify any index for the matrix, sum sums all its values.

From reading the blog and the little experiment, I think that your custom functions work in cases where the used function processes provided data and is able to operate with missing arguments. In case of subsetting a matrix, the behaviour with missing arguments for subsets is that the function performs an operation over the whole dataset.

2
votes

My guess is the argument is never evaluated.

foo <- function(x)
    bar(x)

bar <- function(y)
    missing(y)

foo()
#[1] TRUE
foo(43)
#[1] FALSE

The inner function, in your case [, which has formal arguments i, j, ..., drop = FALSE, most likely checks whether the argument j is missing, and if it is missing it doesn't try to evaluate it.

0
votes

In addition to @nya answer:

You can avoid this behavior by inserting an if-statement inside the function, that assesses whether or a value for j has been supplied when calling the function. If no value is supplied, the function will throw an error:

foo <- function(mat, j){
   if(missing(j)){                # Check if argument for j has been supplied
       error("j is not inserted")
   } else{
       v <- sum(mat[,j])
       return(v)
     }
   }