Re: [S] deparse+substitute

Ray Brownrigg (Ray.Brownrigg@mcs.vuw.ac.nz)
Tue, 28 Apr 1998 13:54:13 +1200 (NZST)


Paul Quataert <Paul.Quataert@ihe.be> asked:

> I want to use the deparse(substitute()) combination
> to create labels, e.g.
> tstS <- function(xv) deparse(substitute(xv))
> Then I get for
> tstS(letters)
> [1] "letters"
>
> Everything is OK for now. However this trick does not
> work anymore when I use tstS as a subroutine in another
> procedure, e.g.
> tstM <- function(...) tstS(...)
> Then I get
> tstM(xv=letters)
> [1] "..1"
> which is the name of the variable in tstM, and not the
> name of the original variable.
>
> Does there exist a DIRECT way to fix this problem ?
>
Bill Venables <wvenable@attunga.stats.adelaide.edu.au> responded:
>
> I'm going to stick my neck out and say I suspect it is not
> possible, for the simple reason that S has a strict call-by-value
> protocol. The name of the object is not transmitted to the
> function so it cannot be transmitted further to another function.
>
> Given that you can always reach up to the parent frame and indeed
> to its parent, and so forth, you can often apparently bypass this
> rule, as, for example fix() does. It effectively has a
> call-by-name protocol, but it, too, only works at one frame apart
> from the object.
>
and Patrick Burns <pburns@pburns.seanet.com> also:
>
> I'm sure there are better ways, but here is the first one that
> worked for me. This technique is going to get pretty messy if
> you traverse a few more levels.
>
> > tstM
> function(...)
> tstS(...)
> > tstS
> function(xv)
> {
> deparse(eval(parse(text = paste("substitute(",
> deparse(substitute(xv)),
> ",sys.parent())"))))
> }
>
> > tstM(4:6)
> [1] "4:6"
> > tstM(xv=letters)
> [1] "letters"

Here is another possibility which as far as I can see does not suffer
from either problem of having to redefine functions based on the name of
the variables you intend to use, or on the depth of use of the name:

> tstM <- function(...)
tstS(...)
> tstS <- function(xv)
attributes(xv)$label
> label <- function(x, label = deparse(substitute(x)))
{
attributes(x)[["label"]] <- label
invisible(assign(deparse(substitute(x)), x, 0))
}
>
Use as follows:
> label(letters)
> tstM(letters)
[1] "letters"
> tstM(y)
NULL
>

What you do have to do is "label" (using the function label()) each
function you want to use in this way. This temporarily attaches a label
which can be used at any level further down. However, while label() may
be used at any level, its actual parameter must be an actual function
name, not a formal parameter.

A distinct disadvantage is that every object so labelled is kept in
memory in the session frame. If you have enough memory, this may be an
advantage ...

Hope this helps,
Ray Brownrigg
-----------------------------------------------------------------------
This message was distributed by s-news@wubios.wustl.edu. To unsubscribe
send e-mail to s-news-request@wubios.wustl.edu with the BODY of the
message: unsubscribe s-news