[R] splitting up optional args
Prof Brian Ripley
ripley at stats.ox.ac.uk
Mon Feb 12 00:38:49 CET 2001
If you look at some examples, I think that you will see that quite often
NULL is used to indicate your DEFAULT.
Also, missingness is passed down in R but not S, so
foo <- function(x, control)
{
if(missing(control)) cat("using default control\n")
}
plotfoo <- function(x, foocontrol) { foo(x, control=foocontrol)}
> plotfoo(1:10)
using default control
does work, although you have to use an explicit test for missingness.
The more common version is
foo <- function(x, control=NULL)
{
if(is.null(control)) cat("using default control\n")
}
plotfoo <- function(x, foocontrol=NULL) { foo(x, control=foocontrol)}
I have yet to see an example in which these did not suffice, and I've been
doing this for more than a decade.
On Sun, 11 Feb 2001, Jason Eisner wrote:
> A question (& possible suggestion) about function calls.
>
> Is there an R idiom to eliminate the redundancy in the
> following common situation?
>
> foo <- function(x, control=ComplicatedDefault) { etc. }
>
> plotfoo <- function(x, foocontrol=ComplicatedDefault, ...) {
> y <- foo(x, control=foocontrol)
> lines(x,y,...) }
>
> The idea is that there are MANY optional parameters to plotfoo().
> Any specified value for foocontrol should be passed to foo(), and the
> other options should be passed to lines() via "...".
>
> The main trouble above is that the same default for foo()'s control
> parameter has to be specified in two places. This makes it hard to
> maintain the code correctly.
>
> Further trouble with the above example becomes clear if we elaborate
> it a bit:
>
> plotfoo <- function(x, foocontrol=ComplicatedDefault, ...) {
> y <- foo(x, control=foocontrol)
> z <- foo(x+1, control=foocontrol)
> lines(x,y,...) # respect lines()'s defaults
> par(col=3) # change lines()'s defaults
> lines(x,z,...) # respect new defaults
> points(x,y+z,...) } # respect points()'s defaults
>
> When we call plotfoo(x), ComplicatedDefault is evaluated in plotfoo's
> environment rather than foo's, and it is only evaluated once even
> though we call foo twice. This is not the same as if plotfoo simply
> didn't specify a control parameter when calling foo. It also
> contrasts with the behavior of the unnamed optional arguments picked
> up by "...". For example, the default for the graphical parameter col
> is evaluated in the environment of the callee (lines or points) and is
> evaluated separately for each callee and on each call.
>
> To eliminate the redundancy, I think one could write:
>
> plotfoo <- function(x, foocontrol=eval(formals(foo)$control), ...) {etc}
>
> This is not terrible, but it is obscure for such a common situation,
> and not mentioned in the documentation. And it does not solve
> the evaluation problems mentioned above.
>
> Would it therefore make sense to extend R to allow the following?
>
> plotfoo <- function(x, foocontrol=, ...) { # currently illegal
> y <- foo(x, control=foocontrol)
> plot(x,y,...) }
>
> The rationale is that one can already call foo(x, control=) to request
> the default control argument for foo. Notionally, there is a special
> "empty" value here that says "give me the default." So it would be
> nice to be able to pass that empty value down the call stack.
>
> The user presumably shouldn't be able to do much with this empty value
> except to pass it as a parameter. Indeed the empty value is
> appropriately analogous to "..." in that it has such restricted use.
>
> I do recognize that since the user can inspect (and construct?) code,
> an expression for the empty value would be accessible as
> formals(plotfoo)$foocontrol or as substitute(foocontrol) evaluated
> within plotfoo(x).
>
> But this expression could be unevaluable, just as formals(plotfoo)$x
> is unevaluable. (Of course these two unevaluable expressions should
> be different, so that the user of formals() can see that x is a
> required argument and foocontrol isn't.)
>
> An alternative is to make this expression evaluable. Suppose we say
> that it evaluates to a special object DEFAULT. Then presumably
> there would be no way to distinguish between
> foo(x, control=DEFAULT)
> foo(x, control=)
> foo(x)
> but that seems okay to me. An advantage to this approach is that
> the user could write potentially useful expressions like
> foo(x, control=ifelse(x==0, 3, DEFAULT))
> and plotfoo could perhaps test its argument to find out whether
> it was DEFAULT, i.e., not specified by the user.
>
> By the way, another use for the proposed extension is as follows:
> plotfoo <- function(x, col=, lty=) { lines(x,foo(x),col=col,lty=lty) }
> This is simply a version of
> plotfoo <- function(x, ...) { lines(x,foo(x), ...) }
> that restricts the caller to certain named parameters, for safety.
>
> I am an R novice and have undoubtedly have missed some considerations
> here, so would be interested in any response from the experts. Thanks!
> -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
> r-help mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
> Send "info", "help", or "[un]subscribe"
> (in the "body", not the subject !) To: r-help-request at stat.math.ethz.ch
> _._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
>
--
Brian D. Ripley, ripley at stats.ox.ac.uk
Professor of Applied Statistics, http://www.stats.ox.ac.uk/~ripley/
University of Oxford, Tel: +44 1865 272861 (self)
1 South Parks Road, +44 1865 272860 (secr)
Oxford OX1 3TG, UK Fax: +44 1865 272595
-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
r-help mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
Send "info", "help", or "[un]subscribe"
(in the "body", not the subject !) To: r-help-request at stat.math.ethz.ch
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
More information about the R-help
mailing list