Question

I'm not sure if I labelled my question correct, but I give it a shot:

I want to use a package with a function which uses an ellipsis, func(...). All my arguments of class My_Class are in a list. As I have quite a lot of arguments, I'd like to avoid func(arg1, arg2, arg3). So ideally I'd like to do func( my_list ). The problem is that the function looks like this

function(...) {
  cl <- match.call(expand.dots = FALSE)
  names <- lapply(cl[[2]],as.character)  
  ev <- parent.frame()
  classes <- unlist(lapply(names,function(name){class(get(name,envir=ev))}))    
  if( !all( classes == "My_Class" ) ) { 
    stop("an argument to ... is not a My_Class")
  }
}

So passing a list doesn't work.

I also tried func(my_list[[1]], my_list[[2]]) and func(as.expression(my_list[[1]])), but even they do not work. As func treats the arguments as characters, func(my_list[[1]]) becomes chr [1:3] "[[" "my_list" "1" inside, and get(name,envir=ev) crashes. I also tried do.call(func, my_list) but this again crashes as my_list is evaluated, therefore name inside the function is no longer a character but a My_CLass and again get(name,envir=ev) crashes.

So my question: How can I accomplish to hand in a list without changing the package / underlying function? I thought about writing a wrapper, but I'm stuck as I do not even can func(my_list[[1]]) make work. Maybe I'm just missing the correct term for my problem.

Thanks in advance!

Was it helpful?

Solution

This works, but I'm mystified by the design choices in that function:

lst <- list(
  a=structure(1:3, class="My_Class"), 
  b=structure(letters[1:3], class="My_Class")
)
env <- list2env(lst)
call <- as.call(append(list(fun), names(lst)))
eval(call, env)

To trick the function into working, you have to evaluate it in an environment where your list items are objects (this is what list2env does, creates that environment).

The terrible thing about that function is that it looks up objects in parent.frame based on their names, assuming that the ... values are indeed names. I really don't understand why that function doesn't just do something like:

if(!all(vapply(list(...), class, "") == "My_Class")) stop(...)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top