Re: [R] The evaluation of optional function arguments

2008-10-20 Thread Sietse Brouwer
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 [EMAIL PROTECTED] 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 -- [EMAIL PROTECTED] -- +31 6 13456848
 Wildekamp 32 -- 6721 JD Bennekom -- the Netherlands
 MSN: [EMAIL PROTECTED] -- 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.


[R] The evaluation of optional function arguments

2008-10-19 Thread Sietse Brouwer
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 -- [EMAIL PROTECTED] -- +31 6 13456848
Wildekamp 32 -- 6721 JD Bennekom -- the Netherlands
MSN: [EMAIL PROTECTED] -- 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.