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 <ruipbarra...@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

Reply via email to