Skip to content

dubious behaviour of match.arg() with nested functions.

6 messages · Hadley Wickham, Gabriel Becker, Peter Dalgaard +2 more

#
Dear all,

I initially ran into this problem while rebuilding a package dependent on
nleqslv. I got the following error:

Error in match.arg(global) : 'arg' must be of length 1

This didn't occur in previous versions of nleqslv, but did in the current
one (2.4). I think I pinned the problem down to the following example:

Take two functions:

test <- function(x=c("q","r","s"),global=c("d","e","r","z","q")){
  x <- match.arg(x)
  global <- match.arg(global)
  return(list(x,global))
}

test2 <- function(x=c("q","r","s"),global=c("d","z","q")){
  test(x=x,global=global)
}

test2() calls an "internal" function test() that uses the same arguments.
Note that for x both functions have exactly the same defaults, but not for
global.

Calling test2() gives the reported error:
Error in match.arg(global) : 'arg' must be of length 1

I see the point of this error (global is not seen by test2() as default
settings but as a character vector I presume), but I wonder why this isn't
the case for x. Is this by design? If so, is there a part of the manual I
overlooked?

Cheers
Joris
#
This is one of the perils of non-standard evaluation - functions are
no longer referentially transparent.

Hadley
On Mon, Aug 25, 2014 at 9:27 AM, Joris Meys <jorismeys at gmail.com> wrote:

  
    
#
More specifically, you're satisifying and not satisfying

    if (identical(arg, choices))
        return(arg[1L])

within the definition of match.args for x, and global, respectively.

arg is what is passed to the function (outer default) but choices isn't
specified so match.args uses nonstandard evaluation to populate it with the
default value *in the the call frame from which match.args was called*,
i.e. the *inner* default value. (See the details section of ?match.args)

The take away here is that match.args without explicitly setting choices is
dangerous except in top level functions, and that more generally
non-standard evaluation is dangerous and should be used sparingly and with
care.

~G
On Mon, Aug 25, 2014 at 8:22 AM, Hadley Wickham <h.wickham at gmail.com> wrote:

            

  
    
#
On 25 Aug 2014, at 16:27 , Joris Meys <jorismeys at gmail.com> wrote:

            
What you are experiencing would seem to amount to this:
[1] "a"
Error in match.arg(x) : 'arg' must be of length 1

Words to that effect appear in the Details section of ?match.arg

-Peter D
#
On 25-08-2014, at 16:27, Joris Meys <jorismeys at gmail.com> wrote:

            
Can?t  the problem easily be avoided by using a slightly modified version of the test2() function?

test2 <- function(x=c("q","r","s"),global=c("d","z","q")){
 x <- match.arg(x)
global <- match.arg(global)
 test(x=x,global=global)
}

Then test2() would be calling test() as it was intended to be called.
I?ve tried that and it appears to solve the problem.

So before calling nleqslv within another function use match.arg on those arguments with the same name and different defaults.
And (possibly) document that some arguments expect a single value.

Berend
#
Dear all,

thank you for the explanations, crystal clear now. I'm also officially an
idiot. Functions in files in a package belong to that package and not to
some other package that happens to appear in the name of said function. Ah,
the merits of inheritance (inheriting a complex code base in this case...)

Cheers
Joris
On Mon, Aug 25, 2014 at 6:49 PM, Berend Hasselman <bhh at xs4all.nl> wrote: