shadow
shadow

Reputation: 22293

different behaviors when passing empty ellipsis arguments

This answer brought up the question of how the ellipsis feature in R handles empty arguments. Apparently an empty argument in ... works sometimes (see lapply version below) but not other times (see sapply version). Here's the example:

lst <- list(x=matrix(1))
lapply(lst, "[", 1, )
# $x
# [1] 1
sapply(lst, "[", 1, )
# Error in lapply(X = X, FUN = FUN, ...) : 
#   argument is missing, with no default

From what I can tell, sapply actually just reuses its ... arguments when calling lapply. So I don't understand why lapply works but sapply doesn't. Can anybody explain this behavior.

In the sapply help it states that

sapply(*, simplify = FALSE, USE.NAMES = FALSE) is equivalent to lapply(*).

However, I get the same results as above for the following:

lapply(lst, "[", i=1, j=)
sapply(lst, "[", i=1, j=, simplify=FALSE, USE.NAMES=FALSE)

By the way, I know that just adding TRUE would solve the issue in this case, but I'm more interested in why there is a difference, not how to solve it. I'm actually more surprised that it works for the lapply case than that it doesn't for the sapply one.

Upvotes: 4

Views: 380

Answers (1)

James Tobin
James Tobin

Reputation: 3110

Because I am not a C master, at all, I can only show you what the differences are between how sapply and lapply are represented internally. And maybe someone else can build on this answer a little bit.

So for sapply: we'll look at https://github.com/SurajGupta/r-source/blob/master/src/library/base/R/sapply.R

And for lapply: https://github.com/SurajGupta/r-source/blob/master/src/library/base/R/lapply.R

This shows that although sapply calls lapply it then also calls simplify2array which could be one of the issues, but my intuition is telling me that this isn't the issue.

lapply ends up using .Internal(lapply(X,FUN)) which ends up calling do_lapply within the C source code here: https://github.com/SurajGupta/r-source/blob/91aaa43312da6b0e6906ef221fd7756dc0459843/src/main/apply.c

My guess is that because sapply inherently passes two parameters into SEXP args the ... argument is trying to create the SEXP args of sapply with everything after sapply(lst, "[", and because it can't figure out what to do with either 1, or j= before it gets to simplify=FALSE, USE.NAMES=FALSE, it fails. Although that would just be my guess. Whereas lapply doesn't have the additional arguments being forced into SEXP args so it can handle 1, or j= in a different way.

This post, Understanding how .Internal C functions are handled in R, does a very nice job explaining some of the nitty-gritty C stuff.

Hope this helps explain the differences to some degree, or at least can serve as a starting point for someone with greater R-devel skills.

Upvotes: 1

Related Questions