[Rd] ...()

Simon Urbanek @|mon@urb@nek @end|ng |rom R-project@org
Sun Aug 28 02:17:23 CEST 2022


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 using 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 using r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
> 



More information about the R-devel mailing list