[prev in list] [next in list] [prev in thread] [next in thread]
List: r-devel
Subject: Re: [Rd] ...()
From: Simon Urbanek <simon.urbanek () R-project ! org>
Date: 2022-08-28 0:17:23
Message-ID: 634DBFC2-76FE-4AF0-A020-37210DBA8975 () R-project ! org
[Download RAW message or body]
Someone with historical knowledge may shed more light on whether this was ever \
intended in the language, but based on the current implementation I would say that \
this is a (perhaps convenient) side-effect of how substitute works and not an \
explicitly defined behavior (since there is no special handling for this "feature" in \
the sources). Probably best illustrated with
> .Internal(inspect(quote(...())))
@1292a4d60 06 LANGSXP g0c0 [REF(2)]
@13880d730 01 SYMSXP g0c0 [MARK,REF(65535)] "..."
> .Internal(inspect(quote(...(...))))
@129293838 06 LANGSXP g0c0 [REF(2)]
@13880d730 01 SYMSXP g0c0 [MARK,REF(65535)] "..."
@13880d730 01 SYMSXP g0c0 [MARK,REF(65535)] "..."
> f = function (...) substitute(...(...))
> str(f(a=g(),b))
Dotted pair list of 4
$ a: language g()
$ : symbol b
$ a: language g()
$ : symbol b
The key here is that call to `...` is simply a LANGSXP with `...` alone, so \
substitute will start its substitution of that call pairlist thus yielding just the \
substituted arguments as there is nothing else. And it will also carry on if anything \
else follows as illustrated above (i.e. if the call pairlist has more than one \
element). As the substitute documentation warns it's not guaranteed to make any \
sense.
So my take would be that this is not documented, because it's not guaranteed \
(although I don't see why it should break anytime soon). It may make sense to think \
about it and define the desired behavior (e.g., I would argue that the above is not \
necessarily desired).
If one is to think about this special case, then in theory one may expect \
substitute(...) to work, but it doesn't since the arguments get matched to the \
formals first before substitute gets to them, so something is necessary that makes \
`...` into a single object -- and ...() seems to fit the bill since it's a single \
call. As noted in the thread that Rui posted, the way to do this without relying on \
undefined behavior is to use a regular call and drop the head:
> f = function (...) as.list(substitute(.(...)))[-1]
> str(f(a=g(),b))
List of 2
$ a: language g()
$ : symbol b
Cheers,
Simon
> On Aug 28, 2022, at 5:23 AM, Rui Barradas <ruipbarradas@sapo.pt> wrote:
>
> Hello,
>
> I don't believe it is documented but the best I could find was this not very old \
> r-devel thread [1].
> [1] https://stat.ethz.ch/pipermail/r-devel/2020-March/079131.html
>
> Hope this helps,
>
> Rui Barradas
>
> Às 18:04 de 27/08/2022, Gabor Grothendieck escreveu:
> > I was looking for the documentation for ...() but it is not in ?dots
> > (where ...length(), ...names(), etc. are documented) and google seems
> > challenged with this one. Is this documented anywhere?
> > e.g.
> > f <- function(...) substitute(...())
> > f(a, b)
> > ## [[1]]
> > ## a
> > ##
> > ## [[2]]
> > ## b
> >
>
> ______________________________________________
> R-devel@r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>
______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic