Expanding partial names

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

Expanding partial names

Duncan Murdoch
I'm writing wrappers for some functions that change some of the default
arguments.  I'd rather not list all of the arguments for the low level
functions because there are about a dozen wrapper functions, and about
20 arguments to lowlevel.  Instead I'm trying something like this:

lowlevel <- function(longname = 1) {
   cat("longname = ", longname, "\n")
}

wrapper <- function(...) {
   newargs <- list(longname = 2)
   newargs[names(list(...))] <- list(...)
   do.call("lowlevel", newargs)
}

This almost works:

 > wrapper()
longname =  2
 > wrapper(longname = 3)
longname =  3

But it fails if I try to use partial argument matching:

 > wrapper(long=4)
Error in lowlevel(longname = 2, long = 4) :
         unused argument(s) (long ...)

because long isn't matched to longname.  Is there a reasonable way to do
this (e.g. using pmatch or charmatch) other than listing all the low
level arguments in the argument list to wrapper?

Duncan Murdoch

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Expanding partial names

Gabor Grothendieck
Try this:


wrapper <- function(...) {
  args <- list(...)
  if (length(args)) {
          nf <- names(formals(lowlevel))
          nams <- nf[pmatch(names(args), nf)]
          args <- replace(list(longname = 2), nams, args)
  }
  do.call("lowlevel", args)
}

Here is a test:

> wrapper()
longname =  1
> wrapper(longname = 34)
longname =  34
> wrapper(long = 34)
longname =  34


On 3/7/06, Duncan Murdoch <[hidden email]> wrote:

> I'm writing wrappers for some functions that change some of the default
> arguments.  I'd rather not list all of the arguments for the low level
> functions because there are about a dozen wrapper functions, and about
> 20 arguments to lowlevel.  Instead I'm trying something like this:
>
> lowlevel <- function(longname = 1) {
>   cat("longname = ", longname, "\n")
> }
>
> wrapper <- function(...) {
>   newargs <- list(longname = 2)
>   newargs[names(list(...))] <- list(...)
>   do.call("lowlevel", newargs)
> }
>
> This almost works:
>
>  > wrapper()
> longname =  2
>  > wrapper(longname = 3)
> longname =  3
>
> But it fails if I try to use partial argument matching:
>
>  > wrapper(long=4)
> Error in lowlevel(longname = 2, long = 4) :
>         unused argument(s) (long ...)
>
> because long isn't matched to longname.  Is there a reasonable way to do
> this (e.g. using pmatch or charmatch) other than listing all the low
> level arguments in the argument list to wrapper?
>
> Duncan Murdoch
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Expanding partial names

Duncan Murdoch
On 3/7/2006 9:42 AM, Gabor Grothendieck wrote:

> Try this:
>
>
> wrapper <- function(...) {
>   args <- list(...)
>   if (length(args)) {
>  nf <- names(formals(lowlevel))
>  nams <- nf[pmatch(names(args), nf)]
>  args <- replace(list(longname = 2), nams, args)
>   }
>   do.call("lowlevel", args)
> }
>
> Here is a test:
>
>> wrapper()
> longname =  1
>> wrapper(longname = 34)
> longname =  34
>> wrapper(long = 34)
> longname =  34

Thanks, that's getting close, but it doesn't quite handle errors cleanly:

 > wrapper(junk=3)
Error in lowlevel(longname = 2, "NA" = 3) :
         unused argument(s) (NA ...)

It looks like I'll need something fairly elaborate.

Duncan Murdoch

> On 3/7/06, Duncan Murdoch <[hidden email]> wrote:
>> I'm writing wrappers for some functions that change some of the default
>> arguments.  I'd rather not list all of the arguments for the low level
>> functions because there are about a dozen wrapper functions, and about
>> 20 arguments to lowlevel.  Instead I'm trying something like this:
>>
>> lowlevel <- function(longname = 1) {
>>   cat("longname = ", longname, "\n")
>> }
>>
>> wrapper <- function(...) {
>>   newargs <- list(longname = 2)
>>   newargs[names(list(...))] <- list(...)
>>   do.call("lowlevel", newargs)
>> }
>>
>> This almost works:
>>
>>  > wrapper()
>> longname =  2
>>  > wrapper(longname = 3)
>> longname =  3
>>
>> But it fails if I try to use partial argument matching:
>>
>>  > wrapper(long=4)
>> Error in lowlevel(longname = 2, long = 4) :
>>         unused argument(s) (long ...)
>>
>> because long isn't matched to longname.  Is there a reasonable way to do
>> this (e.g. using pmatch or charmatch) other than listing all the low
>> level arguments in the argument list to wrapper?
>>
>> Duncan Murdoch
>>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Expanding partial names

Gabor Grothendieck
The original code was not intended to be fully finished.
It was just to give the idea so I left out the error checking.
Adding such a check is just a matter of adding an if
statement to check the pmatch for NA:

wrapper <- function(...) {
  args <- list(...)
  if (length(args)) {
     nf <- names(formals(lowlevel))
     idx <- pmatch(names(args), nf)
     if (any(is.na(idx)))
        stop(paste("Invalid names used:", names(args)[is.na(idx)]))
     nams <- nf[idx]
     args <- replace(list(longname = 2), nams, args)
  }
  do.call("lowlevel", args)
}

wrapper(long = 3)
wrapper(junk = 5)

On 3/7/06, Duncan Murdoch <[hidden email]> wrote:

> On 3/7/2006 9:42 AM, Gabor Grothendieck wrote:
> > Try this:
> >
> >
> > wrapper <- function(...) {
> >   args <- list(...)
> >   if (length(args)) {
> >         nf <- names(formals(lowlevel))
> >         nams <- nf[pmatch(names(args), nf)]
> >         args <- replace(list(longname = 2), nams, args)
> >   }
> >   do.call("lowlevel", args)
> > }
> >
> > Here is a test:
> >
> >> wrapper()
> > longname =  1
> >> wrapper(longname = 34)
> > longname =  34
> >> wrapper(long = 34)
> > longname =  34
>
> Thanks, that's getting close, but it doesn't quite handle errors cleanly:
>
>  > wrapper(junk=3)
> Error in lowlevel(longname = 2, "NA" = 3) :
>         unused argument(s) (NA ...)
>
> It looks like I'll need something fairly elaborate.
>
> Duncan Murdoch
>
> > On 3/7/06, Duncan Murdoch <[hidden email]> wrote:
> >> I'm writing wrappers for some functions that change some of the default
> >> arguments.  I'd rather not list all of the arguments for the low level
> >> functions because there are about a dozen wrapper functions, and about
> >> 20 arguments to lowlevel.  Instead I'm trying something like this:
> >>
> >> lowlevel <- function(longname = 1) {
> >>   cat("longname = ", longname, "\n")
> >> }
> >>
> >> wrapper <- function(...) {
> >>   newargs <- list(longname = 2)
> >>   newargs[names(list(...))] <- list(...)
> >>   do.call("lowlevel", newargs)
> >> }
> >>
> >> This almost works:
> >>
> >>  > wrapper()
> >> longname =  2
> >>  > wrapper(longname = 3)
> >> longname =  3
> >>
> >> But it fails if I try to use partial argument matching:
> >>
> >>  > wrapper(long=4)
> >> Error in lowlevel(longname = 2, long = 4) :
> >>         unused argument(s) (long ...)
> >>
> >> because long isn't matched to longname.  Is there a reasonable way to do
> >> this (e.g. using pmatch or charmatch) other than listing all the low
> >> level arguments in the argument list to wrapper?
> >>
> >> Duncan Murdoch
> >>
> >> ______________________________________________
> >> [hidden email] mailing list
> >> https://stat.ethz.ch/mailman/listinfo/r-devel
> >>
> >
> > ______________________________________________
> > [hidden email] mailing list
> > https://stat.ethz.ch/mailman/listinfo/r-devel
>
>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Expanding partial names

Charles Dupont
In reply to this post by Duncan Murdoch
Duncan Murdoch wrote:

> I'm writing wrappers for some functions that change some of the default
> arguments.  I'd rather not list all of the arguments for the low level
> functions because there are about a dozen wrapper functions, and about
> 20 arguments to lowlevel.  Instead I'm trying something like this:
>
> lowlevel <- function(longname = 1) {
>    cat("longname = ", longname, "\n")
> }
>
> wrapper <- function(...) {
>    newargs <- list(longname = 2)
>    newargs[names(list(...))] <- list(...)
>    do.call("lowlevel", newargs)
> }
>
> This almost works:
>
>  > wrapper()
> longname =  2
>  > wrapper(longname = 3)
> longname =  3
>
> But it fails if I try to use partial argument matching:
>
>  > wrapper(long=4)
> Error in lowlevel(longname = 2, long = 4) :
>          unused argument(s) (long ...)
>
> because long isn't matched to longname.  Is there a reasonable way to do
> this (e.g. using pmatch or charmatch) other than listing all the low
> level arguments in the argument list to wrapper?
>
> Duncan Murdoch

If all you are doing is changing the default values of some arguments
this should work.

wrapper <- lowlevel
formals(wrapper) <- replace(formals(lowlevel), c("longname"), list(2))

Charles

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Expanding partial names

hadley wickham
In reply to this post by Duncan Murdoch
Here's a slightly different approach:

lowlevel <- function(longname = 1, ...) {
  cat("longname = ", longname, "\n")
}

wrapper <- function(...) {
  newargs <- defaults(list(...), list(longname = 2))
  do.call("lowlevel", newargs)
}

defaults <- function(x, defaults)  {
        if (length(x) == 0) return(defaults)
        names(x) <- ifelse(is.na(pmatch(names(x), names(defaults))),
names(x), names(defaults))
        c(x, defaults[setdiff(names(defaults), names(x))])
}

wrapper()
wrapper(longname=20)
wrapper(long=20)
wrapper(junk=3)


Hadley

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Expanding partial names

Duncan Murdoch
In reply to this post by Charles Dupont
On 3/7/2006 12:08 PM, Charles Dupont wrote:

> Duncan Murdoch wrote:
>> I'm writing wrappers for some functions that change some of the default
>> arguments.  I'd rather not list all of the arguments for the low level
>> functions because there are about a dozen wrapper functions, and about
>> 20 arguments to lowlevel.  Instead I'm trying something like this:
>>
>> lowlevel <- function(longname = 1) {
>>    cat("longname = ", longname, "\n")
>> }
>>
>> wrapper <- function(...) {
>>    newargs <- list(longname = 2)
>>    newargs[names(list(...))] <- list(...)
>>    do.call("lowlevel", newargs)
>> }
>>
>> This almost works:
>>
>>  > wrapper()
>> longname =  2
>>  > wrapper(longname = 3)
>> longname =  3
>>
>> But it fails if I try to use partial argument matching:
>>
>>  > wrapper(long=4)
>> Error in lowlevel(longname = 2, long = 4) :
>>          unused argument(s) (long ...)
>>
>> because long isn't matched to longname.  Is there a reasonable way to do
>> this (e.g. using pmatch or charmatch) other than listing all the low
>> level arguments in the argument list to wrapper?
>>
>> Duncan Murdoch
>
> If all you are doing is changing the default values of some arguments
> this should work.
>
> wrapper <- lowlevel
> formals(wrapper) <- replace(formals(lowlevel), c("longname"), list(2))

Thanks for the suggestion, but the calculation of the new defaults is
more involved than my example indicated.  I really need to do some
computation within the wrapper to come up with the new defaults.

Duncan Murdoch

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Expanding partial names

Deepayan Sarkar
In reply to this post by Duncan Murdoch


On 3/7/06, Duncan Murdoch <[hidden email]> wrote:

> I'm writing wrappers for some functions that change some of the default
> arguments.  I'd rather not list all of the arguments for the low level
> functions because there are about a dozen wrapper functions, and about
> 20 arguments to lowlevel.  Instead I'm trying something like this:
>
> lowlevel <- function(longname = 1) {
>    cat("longname = ", longname, "\n")
> }
>
> wrapper <- function(...) {
>    newargs <- list(longname = 2)
>    newargs[names(list(...))] <- list(...)
>    do.call("lowlevel", newargs)
> }
>
> This almost works:
>
>  > wrapper()
> longname =  2
>  > wrapper(longname = 3)
> longname =  3
>
> But it fails if I try to use partial argument matching:
>
>  > wrapper(long=4)
> Error in lowlevel(longname = 2, long = 4) :
>          unused argument(s) (long ...)
>
> because long isn't matched to longname.  Is there a reasonable way to do
> this (e.g. using pmatch or charmatch) other than listing all the low
> level arguments in the argument list to wrapper?

One trick I often use that is different from any of the suggestions I have seen so far (and is more transparent IMO) is the following:


lowlevel <- function(longname = 1) {
   cat("longname = ", longname, "\n")
}

wrapper <- function(...) {
    newArgs <-
        function(longname = 2, ...)
            list(longname = longname,
                 ...)
    do.call("lowlevel", newArgs(...))
}

which gives:

> wrapper()
longname =  2
> wrapper(longname = 3)
longname =  3
> wrapper(long=20)
longname =  20
> wrapper(junk=3)
Error in lowlevel(longname = 2, junk = 3) :
        unused argument(s) (junk ...)

-Deepayan

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Expanding partial names

Duncan Murdoch
On 3/7/2006 2:00 PM, Deepayan Sarkar wrote:

>
> On 3/7/06, Duncan Murdoch <[hidden email]> wrote:
>> I'm writing wrappers for some functions that change some of the default
>> arguments.  I'd rather not list all of the arguments for the low level
>> functions because there are about a dozen wrapper functions, and about
>> 20 arguments to lowlevel.  Instead I'm trying something like this:
>>
>> lowlevel <- function(longname = 1) {
>>    cat("longname = ", longname, "\n")
>> }
>>
>> wrapper <- function(...) {
>>    newargs <- list(longname = 2)
>>    newargs[names(list(...))] <- list(...)
>>    do.call("lowlevel", newargs)
>> }
>>
>> This almost works:
>>
>>  > wrapper()
>> longname =  2
>>  > wrapper(longname = 3)
>> longname =  3
>>
>> But it fails if I try to use partial argument matching:
>>
>>  > wrapper(long=4)
>> Error in lowlevel(longname = 2, long = 4) :
>>          unused argument(s) (long ...)
>>
>> because long isn't matched to longname.  Is there a reasonable way to do
>> this (e.g. using pmatch or charmatch) other than listing all the low
>> level arguments in the argument list to wrapper?
>
> One trick I often use that is different from any of the suggestions I have seen so far (and is more transparent IMO) is the following:

Thanks, this is a nice idea.  It looks as though it would combine well
with Charles Duponts' suggestion to change the formals, i.e. I could
have a generic version of your newArgs function, then change the formals
and the body to match the pattern you used.

One thing I'd like is to be able to put the new defaults in a list,
because this code is going to show up in about a dozen places, and I
don't want to have to edit all of them when the arg list of the low
level function changes.  So really I want something like

newArgs(..., newDefaults)

where newDefaults is a tagged list (e.g. list(longname = 2) for the
example below), and the return value is a list containing all the names
in newDefaults, perhaps with their values modified according to the args
passed in ... .

In the actual use newDefaults would be the result of a function call
(the user will have made some configuration choices and I want those to
be used as defaults to another function) but that's not so important
here.  I'd like the wrapper to be a bit like par(), though I notice that
par() doesn't accept partial name matching so maybe I'm worrying about
something I shouldn't.

Duncan Murdoch

>
>
> lowlevel <- function(longname = 1) {
>    cat("longname = ", longname, "\n")
> }
>
> wrapper <- function(...) {
>     newArgs <-
>         function(longname = 2, ...)
>             list(longname = longname,
>                  ...)
>     do.call("lowlevel", newArgs(...))
> }
>
> which gives:
>
>> wrapper()
> longname =  2
>> wrapper(longname = 3)
> longname =  3
>> wrapper(long=20)
> longname =  20
>> wrapper(junk=3)
> Error in lowlevel(longname = 2, junk = 3) :
> unused argument(s) (junk ...)
>
> -Deepayan
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Expanding partial names

Duncan Murdoch
Okay, here's my effort based on Deepayan's and Charles' ideas.  The
newArgs function is not what I'd call transparent, but I like the way
the wrapper looks.

 > newArgs <- function(..., Params) {
+   f <- function(...) list(...)
+   formals(f) <- c(Params, formals(f))

+   b <- as.list(body(f))
+   body(f) <- as.call(c(b[1], names, b[-1]))
+   f(...)
+ }
 >
 > lowlevel <- function(longname = 1) {
+   cat("longname = ", longname, "\n")
+ }
 >
 > newDefaults <- list(longname=2)
 >
 > wrapper <- function (...)
+   do.call("lowlevel", newArgs(..., Params=newDefaults))

newArgs sets up f to look like

function (longname = 2, ...) list(longname = longname, ...)

and then calls it.  The thing I like about this, as opposed to using
pmatch, is that I'm sure the partial matching is what's used by R's
argument matching, whereas that's only pretty likely with pmatch.

I also sort of like these lines:

+   names <- as.list(names(Params))
+   names(names) <- names
+   names <- lapply(names, as.name)

but maybe I should have named Params as names, so they looked like this:

+   names <- as.list(names(names))
+   names(names) <- names
+   names <- lapply(names, as.name)

And of course I like the fact that this seems to work, but we've seen
several versions that do that:

 > wrapper()
longname =  2
 > wrapper(longname=3)
longname =  3
 > wrapper(long=3)
longname =  3
 > wrapper(long=20)
longname =  20
 > wrapper(junk=20)
Error in lowlevel(longname = 2, junk = 20) :
         unused argument(s) (junk ...)

Duncan Murdoch

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Expanding partial names

Duncan Murdoch
Whoops, just noticed that I cut when I should have copied.  The newArgs
function should look like this:

newArgs <- function(..., Params) {
   f <- function(...) list(...)
   formals(f) <- c(Params, formals(f))
   names <- as.list(names(Params))
   names(names) <- names
   names <- lapply(names, as.name)
   b <- as.list(body(f))
   body(f) <- as.call(c(b[1], names, b[-1]))
   f(...)
}

Duncan Murdoch

On 3/7/2006 9:18 PM, Duncan Murdoch wrote:

> Okay, here's my effort based on Deepayan's and Charles' ideas.  The
> newArgs function is not what I'd call transparent, but I like the way
> the wrapper looks.
>
>  > newArgs <- function(..., Params) {
> +   f <- function(...) list(...)
> +   formals(f) <- c(Params, formals(f))
>
> +   b <- as.list(body(f))
> +   body(f) <- as.call(c(b[1], names, b[-1]))
> +   f(...)
> + }
>  >
>  > lowlevel <- function(longname = 1) {
> +   cat("longname = ", longname, "\n")
> + }
>  >
>  > newDefaults <- list(longname=2)
>  >
>  > wrapper <- function (...)
> +   do.call("lowlevel", newArgs(..., Params=newDefaults))
>
> newArgs sets up f to look like
>
> function (longname = 2, ...) list(longname = longname, ...)
>
> and then calls it.  The thing I like about this, as opposed to using
> pmatch, is that I'm sure the partial matching is what's used by R's
> argument matching, whereas that's only pretty likely with pmatch.
>
> I also sort of like these lines:
>
> +   names <- as.list(names(Params))
> +   names(names) <- names
> +   names <- lapply(names, as.name)
>
> but maybe I should have named Params as names, so they looked like this:
>
> +   names <- as.list(names(names))
> +   names(names) <- names
> +   names <- lapply(names, as.name)
>
> And of course I like the fact that this seems to work, but we've seen
> several versions that do that:
>
>  > wrapper()
> longname =  2
>  > wrapper(longname=3)
> longname =  3
>  > wrapper(long=3)
> longname =  3
>  > wrapper(long=20)
> longname =  20
>  > wrapper(junk=20)
> Error in lowlevel(longname = 2, junk = 20) :
>          unused argument(s) (junk ...)
>
> Duncan Murdoch
>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Expanding partial names

Charles Dupont
In reply to this post by Duncan Murdoch
Duncan Murdoch wrote:

> Okay, here's my effort based on Deepayan's and Charles' ideas.  The
> newArgs function is not what I'd call transparent, but I like the way
> the wrapper looks.
>
>  > newArgs <- function(..., Params) {
> +   f <- function(...) list(...)
> +   formals(f) <- c(Params, formals(f))
>
> +   b <- as.list(body(f))
> +   body(f) <- as.call(c(b[1], names, b[-1]))
> +   f(...)
> + }
>  >
>  > lowlevel <- function(longname = 1) {
> +   cat("longname = ", longname, "\n")
> + }
>  >
>  > newDefaults <- list(longname=2)
>  >
>  > wrapper <- function (...)
> +   do.call("lowlevel", newArgs(..., Params=newDefaults))
>
> newArgs sets up f to look like
>
> function (longname = 2, ...) list(longname = longname, ...)
>
> and then calls it.  The thing I like about this, as opposed to using
> pmatch, is that I'm sure the partial matching is what's used by R's
> argument matching, whereas that's only pretty likely with pmatch.
>
> I also sort of like these lines:
>
> +   names <- as.list(names(Params))
> +   names(names) <- names
> +   names <- lapply(names, as.name)
>
> but maybe I should have named Params as names, so they looked like this:
>
> +   names <- as.list(names(names))
> +   names(names) <- names
> +   names <- lapply(names, as.name)
>
> And of course I like the fact that this seems to work, but we've seen
> several versions that do that:
>
>  > wrapper()
> longname =  2
>  > wrapper(longname=3)
> longname =  3
>  > wrapper(long=3)
> longname =  3
>  > wrapper(long=20)
> longname =  20
>  > wrapper(junk=20)
> Error in lowlevel(longname = 2, junk = 20) :
>          unused argument(s) (junk ...)
>

If while running the program you don't need to change either the default
options of the wrapper or the change which lowlevel function is called
this approach works well if you calculations are not too complicated.

createWrapper <- function(FUN, Params) {
   as.function(c(replace(formals(FUN), names(Params), Params),
                 body(FUN)))
}

const <- 10

newDefaults <- alist(cat = 2,
                      longname = if(cat == 2){
                        if(!missing(dog)) cat + dog
                        else cat + 2
                      } else cat * const, dog=)

wrapper <- createWrapper(lowlevel, newDefaults)

 > wrapper()
longname =  4
 > wrapper(longname=3)
longname =  3
 > wrapper(long=3)
longname =  3
 > wrapper(3)
longname =  3
 > wrapper(cat=4)
longname =  40
 > wrapper(dog=6)
longname =  8
 > wrapper(cat=4, dog=6)
longname =  40
 > wrapper(long=3, cat=4, dog=6)
longname =  3

Charles

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel