Ehsan Masoudi
Ehsan Masoudi

Reputation: 712

How to deal with ellipsis (...) in the presence of optional arguments?

I have a problem with ellipsis when I use optional arguments in my function definition. To clarify, I define following functions:

func1 <- function (x) (x-2)^2

func3 <- function (fun, arg.curve.user){
  arg.curve.user$expr <-  substitute(func1)
  arg.curve.default <- list(col = "blue", n = 1000, main = "This is a test")
  arg.curve <- modifyList (arg.curve.default, arg.curve.user)
  do.call("curve", arg.curve)
}

# optimizes func1 and call func2 to plot func1
func2 <- function (lb, ub, n.restarts = 5, n.sim = 10, ...){
  arg.curve.user <- as.list(substitute(list(...)))
  output <- gosolnp(fun = func1, LB = lb, UB = ub,  n.restarts =  n.restarts, 
  n.sim =  n.sim)$par
  func3(fun = func1, arg.curve.user = arg.curve.user)
   return(output)
}

By calling func2, func1 is optimized and also plotted through a func3 call (package Rsolnp is required).

func2 ( lb = 0, ub = 8, n.restarts = 5, n.sim = 10, n = 200, from = 0, to = 8)

But suppose a user misspells n.restarts and writes nrestarts:

func2 ( lb = 0, ub = 8, nrestarts = 5, n.sim = 10, n = 200, from = 0, to = 8)

In this case, I expects R to implement the following plans to deal with absence of n.restarts:

  1. assigns default value, i.e. 5, to n.restarts as an optional argument
  2. declares a warning at the end: "nrestarts" is not a graphical parameter

But this does not happen and R assigns value of n (200) to n.restarts instead!!

Can anyone help me to fix this problem?

Many thanks

Upvotes: 4

Views: 1544

Answers (2)

hadley
hadley

Reputation: 103898

If you stick with regular argument evaluation you are more likely to get warnings off the bat. Again, you don't need to use special evaluation to get the behaviour that you want. Using non-standard evaluation is a bad idea as you are unlikely to exactly reproduce R's default behaviour, causing subtle bugs for you and your users.

library(Rsolnp)

func1 <- function (x) (x-2)^2

func3 <- function (fun, col = "blue", n = 1000, main = "This is a test", ...){
  curve(func1, ..., n = n, col = col, main = main)
}

# optimizes func1 and call func2 to plot func1
func2 <- function (lb, ub, n.restarts = 5, n.sim = 10, ...){
  output <- gosolnp(fun = func1, LB = lb, UB = ub, n.restarts = n.restarts, 
  n.sim =  n.sim)$par
  func3(fun = func1, ...)
  return(output)
}

Then when you run:

func2 ( lb = 0, ub = 8, nrestarts = 5, n.sim = 10, n = 200, from = 0, to = 8)

you get warnings along the lines of

Warning messages:
1: In plot.window(...) : "nrestarts" is not a graphical parameter
2: In plot.xy(xy, type, ...) : "nrestarts" is not a graphical parameter
3: In axis(side = side, at = at, labels = labels, ...) :
  "nrestarts" is not a graphical parameter
4: In axis(side = side, at = at, labels = labels, ...) :
  "nrestarts" is not a graphical parameter
5: In box(...) : "nrestarts" is not a graphical parameter
6: In title(...) : "nrestarts" is not a graphical parameter

Upvotes: 2

Gavin Simpson
Gavin Simpson

Reputation: 174778

It is partial matching the n argument to n.restarts when one is not supplied by the user. Instead, and contrary to the advice of @Andrie (which will work, of course), there is a mechanism that allows you to continue in the manner you have with an argument n and and argument n.restarts. The trick is to place arguments you want to match exactly after the ....

func2 <- function (lb, ub, ..., n.restarts = 5, n.sim = 10){
  writeLines(paste("Value of `n.restarts` is", n.restarts))
  arg.curve.user <- as.list(substitute(list(...)))
  output <- gosolnp(fun = func1, LB = lb, UB = ub,  n.restarts =  n.restarts, 
                    n.sim =  n.sim)$par
  func3(fun = func1, arg.curve.user = arg.curve.user)
  output
}

In use this gives:

> func2 (lb = 0, ub = 8, n.restarts = 2, n.sim = 10, n = 200,
+        from = 0, to = 8)
Value of `n.restarts` is 2          <---- Here!

Iter: 1 fn: 6.926e-15    Pars:  2.00000
Iter: 2 fn: 2.501e-15    Pars:  2.00000
solnp--> Completed in 2 iterations

Iter: 1 fn: 8.336e-16    Pars:  2.00000
Iter: 2 fn: 8.336e-16    Pars:  2.00000
solnp--> Completed in 2 iterations
[1] 2
> func2 (lb = 0, ub = 8, nrestarts = 2, n.sim = 10, n = 200,
+        from = 0, to = 8)
Value of `n.restarts` is 5          <---- Here! Default

Iter: 1 fn: 2.83e-15     Pars:  2.00000
Iter: 2 fn: 2.5e-15  Pars:  2.00000
solnp--> Completed in 2 iterations

Iter: 1 fn: 2.037e-15    Pars:  2.00000
Iter: 2 fn: 2.037e-15    Pars:  2.00000
solnp--> Completed in 2 iterations

Iter: 1 fn: 1.087e-15    Pars:  2.00000
Iter: 2 fn: 1.087e-15    Pars:  2.00000
solnp--> Completed in 2 iterations

Iter: 1 fn: 8.558e-16    Pars:  2.00000
Iter: 2 fn: 8.558e-16    Pars:  2.00000
solnp--> Completed in 2 iterations

Iter: 1 fn: 7.147e-16    Pars:  2.00000
Iter: 2 fn: 7.147e-16    Pars:  2.00000
solnp--> Completed in 2 iterations
[1] 2
Warning messages:
1: In plot.window(...) : "nrestarts" is not a graphical parameter
2: In plot.xy(xy, type, ...) : "nrestarts" is not a graphical parameter
3: In axis(side = side, at = at, labels = labels, ...) :
  "nrestarts" is not a graphical parameter
4: In axis(side = side, at = at, labels = labels, ...) :
  "nrestarts" is not a graphical parameter
5: In box(...) : "nrestarts" is not a graphical parameter
6: In title(...) : "nrestarts" is not a graphical parameter

Upvotes: 8

Related Questions