[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