tags:

views:

48

answers:

2

I have some code where it is more convenient to call fix via do.call, rather than directly. Any old data frame will work for this example:

dfr <- data.frame(x = 1:5, y = letters[1:5])

The obvious first attempt is

do.call("fix", list(dfr))

Unfortunately, this fails with

Error in fix(list(x = 1:5, y = 1:5)) : 'fix' requires a name

So, we give it a name:

do.call("fix", list(dfr = dfr))

This time it fails with

Error in is.name(subx) : 'subx' is missing

For the record, edit doesn't work either.

dfr <- do.call("edit", list(dfr = dfr))

Can anyone think of a sensible workaround, please?

EDIT: Upon reflection, I'd forgotten that fix always dumps its answer into the global environment, which is fine for test examples, but not so good for use with functions. Joshua's excellent workaround doesn't extend to use with edit.

For bonus points, how do you call edit via do.call?

+1  A: 

The first error gives you a hint. This works:

do.call(fix,list("dfr"))

You would still get the same error on your second try even if you used dfr="dfr" because the named list needs names of the arguments to what (the function). So your second try should be:

do.call(fix,list(x="dfr"))
Joshua Ulrich
@Johua: Doh! I feel mildly silly. Cheers.
Richie Cotton
@Richie: try James' answer too, since it's more R-like.
Joshua Ulrich
@Joshua: Marking James as the official answer, on account of how it solves the `edit` problem too, but remind me I owe you an extra upvote for that excellent speedy response.
Richie Cotton
@Richie: no worries; it's the better answer.
Joshua Ulrich
No, this is the better answer because it correctly interprets the input to `fix`.
hadley
@hadley `fix` takes on input either a name or a character string, so surely both answers are correctly interpreting the input
James
@James: The documentation says that `fix` takes a name or character string, but it doesn't really: neither `x <- "mtcars"; fix(x)` or `fix(as.name("mtcars"))` work - I think because the documentation is using name in the non-technical sense. The conclusion is that you're both right, but fix is a horrible function.
hadley
+5  A: 

You can use substitute, which is also useful for when you want to use variable names as labels.

do.call("fix",list(substitute(dfr)))

Edit for clarity

It is easier to see how this works by using the call command:

> call("fix",dfr)
fix(list(x = c(1, 2, 3, 4, 5), y = 1:5))
> call("fix",substitute(dfr))
fix(dfr)

Thus when you use substitute the command that is being created uses the name of the symbol rather than the evaluated symbol. If you wrap an eval around these expressions you see that the first example gives the same error you encountered, and the second example works as expected.

After reading hadley's link it becomes clearer what is being evaluated:

> as.name("dfr")==substitute(dfr)
[1] TRUE
James
This also works for `edit`. Hurrah!
Richie Cotton
I find that any occasion I use `substitute` has typically been preceded by an extended session of programming-induced tourettes. If anyone knows of a simple explanation of how and when to use it, I'd be grateful.
Richie Cotton
It is quite tricky, probably worth another question actually. It basically returns the expression unevaluated, so you can manipulate the underlying expression. Consider the following: `x<-1:10` `printexp <- function(y){paste(substitute(y),"=",deparse(y))}` `printexp(x)` `>"x = 1:10"`
James
@Richie: try http://github.com/hadley/devtools/wiki/Evaluation
hadley
@hadley: Thanks for the link; it's much clearer than the R language manual.
Richie Cotton
You're better off testing for equality with `identical()`
hadley
I think it's better to use `as.name` here because substitute does so many different things so it makes it hard to figure out what's going on. But I really like your explanation now.
hadley