Dear R-helpers, I've got two functions; callTimes() calls times(), passing it an optional argument (bar) by name (bar=harry). times() then believes it has been passed a name, rather than a value ? but I want the value, not the name. Worse, if I evaluate the name, it is evaluated in the environment times() was defined, not where it is called. How can I call times(), defining its optional argument as a variable, and have times() know the variable's value (at the moment of calling)? Below some code: (1) The basic case (2) A working kludge-around (but I'm still looking for the Right Way.) (3) A bunch of variants, so that you may get an idea of the behaviour involved. (3 starts from the simplest case and builds up from there. Think of it as background reading.) Actually, I'll put (1) up here: ######################## ## (1) The basic case ## ## The calling function ## passes an optional argument (bar), as a variable (bar=harry). callTimes <- function(tom, harry) { print(match.call(expand.dots=TRUE)) # callTimes(tom = 2, harry = 7) timesDefineInside(foo=tom, bar=harry) } ## The called function ## does not explicitly ask for bar. timesDefineInside <- function(foo, ...) { # Checks to ensure this code is only executed if bar is given. print(match.call(expand.dots=TRUE)) # times(foo = tom, bar = harry) bar <- match.call(expand.dots=TRUE)$bar print(foo) # [1] 2 print(bar) # harry print(mode(bar)) # "name" print(eval(bar)) # [1] 13 foo*bar # Error in foo * bar : non-numeric argument to binary operator } harry <- 13 # Now, let's see whether it thinks harry==13, or harry==7 callTimes(2, 7) ## For the output, see the above inline comments. ## And THERE we have my problem. I have yet to find a way to call a function, ## give one of the optional arguments as argument=variable, and have it pick up ## on that variable's *value*, rather than its name. (It's not even the ## reference it picks up on: as you can see, if I evaluate the name, it uses ## the definition environment, rather than the calling environment. (For the work-around, scroll down.) A second question, not essential: I spent a while searching on this topic, and found myself unsure of the terminology. Tried a number of things, found nothing, now I'm not sure whether that's because I didn't know the right words. How would you phrase/define this problem? Kind regards, and thanks in advance, Sietse Sietse Brouwer ################# ## Code below. ## ## Two comment-signs for comments, one for output, none for input. ########################## ## (2) A working kludge ## ## I can kludge around it by using callTimes <- function(tom, harry) { timesArgs <- list(foo = tom, bar = harry) do.call(times, timesArgs) } ## ; but is there a Right Way, too? ############################################################ ## (3) Some variants, starting from the simplest case... ## ## ...and increasing in complexity. ## (3.1) This is the function I have trouble with: I can't get it to get bar ## from the arguments. times <- function(foo, ...) { print(match.call(expand.dots=TRUE)) # Some checks and a guard statement. You can safely assume that if there # ain't no bar argument (bar fight?), this part will not be reached. foo*bar } ## here we run it, and see that it gets bar not from ## the argument list, but from the defining environment. ls(bar) # Error in as.environment(pos) : no item called "bar" on the search list times(foo=2, bar=3) # times(foo = 2, bar = 3) # [1] Error in times(foo = 2, bar = 3): object "bar" not found ## Somehow, it doesn't cotton on to the fact that there's a bar ## in the argument list. bar <- 5 times(foo=2, bar=3) # [1] 10 ## Ah. it looks for bar in the environment where the function was defined, not ## in the one where it is evaluated. Lexical scoping, plus a rule of ## inheritance/who's-your-parent-now that I don't quite understand. ## (3.2) Now we try explicitly getting it from the argument list. rm(bar) timesDefineInside <- function(foo, ...) { print(match.call(expand.dots=TRUE)) # again, imagine checks here. bar <- match.call(expand.dots=TRUE)$bar foo*bar } timesDefineInside(foo=7, bar=11) # [1] 77 ## So this works, and all is well, nay? Nay. Turn thou to (1) to see what ## doth happen when we call timesDefineInside from inside another function. -- Sietse Brouwer -- sbbrouwer at gmail.com -- +31 6 13456848 Wildekamp 32 -- 6721 JD Bennekom -- the Netherlands MSN: sietse at gawab.com -- ICQ: 341232104
Try this for timesDefineInside: timesDefineInside <- function(foo, ...) { extra.args <- list(...) bar <- extra.args$bar foo * bar } -Kaom On Oct 19, 2008, at 6:34 PM, Sietse Brouwer wrote:> Dear R-helpers, > > I've got two functions; callTimes() calls times(), passing it an > optional argument (bar) by name (bar=harry). times() then believes it > has been passed a name, rather than a value — but I want the value, > not the name. > Worse, if I evaluate the name, it is evaluated in the environment > times() was defined, not where it is called. > How can I call times(), defining its optional argument as a variable, > and have times() know the variable's value (at the moment of calling)? > > Below some code: > (1) The basic case > (2) A working kludge-around (but I'm still looking for the Right Way.) > (3) A bunch of variants, so that you may get an idea of the > behaviour involved. > > (3 starts from the simplest case and builds up from there. Think of it > as background reading.) > > Actually, I'll put (1) up here: > > ######################## > ## (1) The basic case ## > > ## The calling function > ## passes an optional argument (bar), as a variable (bar=harry). > callTimes <- function(tom, harry) { > print(match.call(expand.dots=TRUE)) # callTimes(tom = 2, harry = 7) > timesDefineInside(foo=tom, bar=harry) > } > > ## The called function > ## does not explicitly ask for bar. > timesDefineInside <- function(foo, ...) { > # Checks to ensure this code is only executed if bar is given. > print(match.call(expand.dots=TRUE)) # times(foo = tom, bar = > harry) > bar <- match.call(expand.dots=TRUE)$bar > print(foo) # [1] 2 > print(bar) # harry > print(mode(bar)) # "name" > print(eval(bar)) # [1] 13 > foo*bar # Error in foo * bar : non-numeric argument to binary > operator > } > > harry <- 13 # Now, let's see whether it thinks harry==13, or harry==7 > callTimes(2, 7) > ## For the output, see the above inline comments. > > ## And THERE we have my problem. I have yet to find a way to call a > function, > ## give one of the optional arguments as argument=variable, and have > it pick up > ## on that variable's *value*, rather than its name. (It's not even > the > ## reference it picks up on: as you can see, if I evaluate the name, > it uses > ## the definition environment, rather than the calling environment. > > (For the work-around, scroll down.) > > A second question, not essential: I spent a while searching on this > topic, and found myself unsure of the terminology. Tried a number of > things, found nothing, now I'm not sure whether that's because I > didn't know the right words. How would you phrase/define this problem? > > Kind regards, and thanks in advance, > > Sietse > Sietse Brouwer > > ################# > ## Code below. ## > ## Two comment-signs for comments, one for output, none for input. > > ########################## > ## (2) A working kludge ## > > ## I can kludge around it by using > callTimes <- function(tom, harry) { > timesArgs <- list(foo = tom, bar = harry) > do.call(times, timesArgs) > } > ## ; but is there a Right Way, too? > > > ############################################################ > ## (3) Some variants, starting from the simplest case... ## > ## ...and increasing in complexity. > > > ## (3.1) This is the function I have trouble with: I can't get it to > get bar > ## from the arguments. > times <- function(foo, ...) { > print(match.call(expand.dots=TRUE)) > # Some checks and a guard statement. You can safely assume that > if there > # ain't no bar argument (bar fight?), this part will not be > reached. > foo*bar > } > > ## here we run it, and see that it gets bar not from > ## the argument list, but from the defining environment. > ls(bar) > # Error in as.environment(pos) : no item called "bar" on the search > list > times(foo=2, bar=3) > # times(foo = 2, bar = 3) > # [1] Error in times(foo = 2, bar = 3): object "bar" not found > ## Somehow, it doesn't cotton on to the fact that there's a bar > ## in the argument list. > bar <- 5 > times(foo=2, bar=3) > # [1] 10 > ## Ah. it looks for bar in the environment where the function was > defined, not > ## in the one where it is evaluated. Lexical scoping, plus a rule of > ## inheritance/who's-your-parent-now that I don't quite understand. > > ## (3.2) Now we try explicitly getting it from the argument list. > rm(bar) > timesDefineInside <- function(foo, ...) { > print(match.call(expand.dots=TRUE)) > # again, imagine checks here. > bar <- match.call(expand.dots=TRUE)$bar > foo*bar > } > timesDefineInside(foo=7, bar=11) > # [1] 77 > > ## So this works, and all is well, nay? Nay. Turn thou to (1) to see > what > ## doth happen when we call timesDefineInside from inside another > function. > > -- > Sietse Brouwer -- sbbrouwer@gmail.com -- +31 6 13456848 > Wildekamp 32 -- 6721 JD Bennekom -- the Netherlands > MSN: sietse@gawab.com -- ICQ: 341232104 > > ______________________________________________ > R-help@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code.[[alternative HTML version deleted]]
Why don't you want to do this? timesDefineInside <- function(foo, bar...) { foo * bar } It seems like the obvious solution to your problem. Hadley On Sun, Oct 19, 2008 at 8:34 PM, Sietse Brouwer <sbbrouwer+r-help at gmail.com> wrote:> Dear R-helpers, > > I've got two functions; callTimes() calls times(), passing it an > optional argument (bar) by name (bar=harry). times() then believes it > has been passed a name, rather than a value ? but I want the value, > not the name. > Worse, if I evaluate the name, it is evaluated in the environment > times() was defined, not where it is called. > How can I call times(), defining its optional argument as a variable, > and have times() know the variable's value (at the moment of calling)? > > Below some code: > (1) The basic case > (2) A working kludge-around (but I'm still looking for the Right Way.) > (3) A bunch of variants, so that you may get an idea of the behaviour involved. > > (3 starts from the simplest case and builds up from there. Think of it > as background reading.) > > Actually, I'll put (1) up here: > > ######################## > ## (1) The basic case ## > > ## The calling function > ## passes an optional argument (bar), as a variable (bar=harry). > callTimes <- function(tom, harry) { > print(match.call(expand.dots=TRUE)) # callTimes(tom = 2, harry = 7) > timesDefineInside(foo=tom, bar=harry) > } > > ## The called function > ## does not explicitly ask for bar. > timesDefineInside <- function(foo, ...) { > # Checks to ensure this code is only executed if bar is given. > print(match.call(expand.dots=TRUE)) # times(foo = tom, bar = harry) > bar <- match.call(expand.dots=TRUE)$bar > print(foo) # [1] 2 > print(bar) # harry > print(mode(bar)) # "name" > print(eval(bar)) # [1] 13 > foo*bar # Error in foo * bar : non-numeric argument to binary operator > } > > harry <- 13 # Now, let's see whether it thinks harry==13, or harry==7 > callTimes(2, 7) > ## For the output, see the above inline comments. > > ## And THERE we have my problem. I have yet to find a way to call a function, > ## give one of the optional arguments as argument=variable, and have it pick up > ## on that variable's *value*, rather than its name. (It's not even the > ## reference it picks up on: as you can see, if I evaluate the name, it uses > ## the definition environment, rather than the calling environment. > > (For the work-around, scroll down.) > > A second question, not essential: I spent a while searching on this > topic, and found myself unsure of the terminology. Tried a number of > things, found nothing, now I'm not sure whether that's because I > didn't know the right words. How would you phrase/define this problem? > > Kind regards, and thanks in advance, > > Sietse > Sietse Brouwer > > ################# > ## Code below. ## > ## Two comment-signs for comments, one for output, none for input. > > ########################## > ## (2) A working kludge ## > > ## I can kludge around it by using > callTimes <- function(tom, harry) { > timesArgs <- list(foo = tom, bar = harry) > do.call(times, timesArgs) > } > ## ; but is there a Right Way, too? > > > ############################################################ > ## (3) Some variants, starting from the simplest case... ## > ## ...and increasing in complexity. > > > ## (3.1) This is the function I have trouble with: I can't get it to get bar > ## from the arguments. > times <- function(foo, ...) { > print(match.call(expand.dots=TRUE)) > # Some checks and a guard statement. You can safely assume that if there > # ain't no bar argument (bar fight?), this part will not be reached. > foo*bar > } > > ## here we run it, and see that it gets bar not from > ## the argument list, but from the defining environment. > ls(bar) > # Error in as.environment(pos) : no item called "bar" on the search list > times(foo=2, bar=3) > # times(foo = 2, bar = 3) > # [1] Error in times(foo = 2, bar = 3): object "bar" not found > ## Somehow, it doesn't cotton on to the fact that there's a bar > ## in the argument list. > bar <- 5 > times(foo=2, bar=3) > # [1] 10 > ## Ah. it looks for bar in the environment where the function was defined, not > ## in the one where it is evaluated. Lexical scoping, plus a rule of > ## inheritance/who's-your-parent-now that I don't quite understand. > > ## (3.2) Now we try explicitly getting it from the argument list. > rm(bar) > timesDefineInside <- function(foo, ...) { > print(match.call(expand.dots=TRUE)) > # again, imagine checks here. > bar <- match.call(expand.dots=TRUE)$bar > foo*bar > } > timesDefineInside(foo=7, bar=11) > # [1] 77 > > ## So this works, and all is well, nay? Nay. Turn thou to (1) to see what > ## doth happen when we call timesDefineInside from inside another function. > > -- > Sietse Brouwer -- sbbrouwer at gmail.com -- +31 6 13456848 > Wildekamp 32 -- 6721 JD Bennekom -- the Netherlands > MSN: sietse at gawab.com -- ICQ: 341232104 > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. >-- http://had.co.nz/
Hullo all, [***recap of the question: passing bar=harry fails when bar is among the ... args.] callTimes <- function(tom, harry) { timesDefineInside(foo=tom, bar=harry } timesDefineInside <- function(foo, ...) { foo * bar } callTimes(3, 4) # Error: object "bar" not found [***end recap] On 20/10/2008, hadley wickham <h.wickham at gmail.com> wrote: > Why don't you want to do this? > > timesDefineInside <- function(foo, bar...) { > foo * bar > } You're right that's it the obvious solution ? the thing is, I'm hacking on somebody else's function, and in the interim I want to maintain backward compatibility. Part of that is expecting the same set of formals, so any extra arguments (in this case, 'bar' is actually 'experimentalMode') have to come throught the dots. Kaom Te wrote: > Try this for timesDefineInside: > timesDefineInside <- function(foo, ...) { > extra.args <- list(...) > bar <- extra.args$bar > foo * bar > } Ah, that works! Apparently, there's a difference between list(...) and match.call(expand.dots=FALSE)$... # wrapped in eval() or not. That makes sense, though, as the first will have evaluated bar=harry at the moment of calling, within the calling function, while the second will evaluated bar=harry within the called function. I think. Thank you both very much; and thanks, too, to Martin Morgan, who replied off-list pointing me at bar <- eval.parent(match.call()$bar) . Grateful regards, Sietse Sietse Brouwer -- Sietse Brouwer -- sbbrouwer at gmail.com -- +31 6 13456848 Wildekamp 32 -- 6721 JD Bennekom -- the Netherlands MSN: sietse at gawab.com -- ICQ: 341232104