From hp@ge@ @ending from fredhutch@org  Tue May  8 18:04:58 2018
From: hp@ge@ @ending from fredhutch@org (=?UTF-8?B?SGVydsOpIFBhZ8Oocw==?=)
Date: Tue, 8 May 2018 09:04:58 -0700
Subject: [Rd] length of `...`
In-Reply-To: <23276.23006.334586.473944@stat.math.ethz.ch>
References: <d0b68216-4922-2249-e5e6-1589345dc6d7@kogentum.hu>
 <CAF8bMcaRW88VdyXw-kmCa9dw-awBiNiU+j+nktLRACCj4grPdQ@mail.gmail.com>
 <37141c6a-831b-b74a-7abf-a36d64130f81@gmail.com>
 <CABdHhvHzGECDQBsZsXTbakNGW7JuX4tw46_KmcYX8_b3kMB=Fg@mail.gmail.com>
 <3ffcd05b-6417-87be-94e0-f621c4a3116b@fredhutch.org>
 <23276.23006.334586.473944@stat.math.ethz.ch>
Message-ID: <2ce4d15c-87c4-68a7-e38c-31baf419ff8a@fredhutch.org>

Thanks Martin for the clarifications.  H.

On 05/04/2018 06:02 AM, Martin Maechler wrote:
>>>>>> Herv? Pag?s <hpages at fredhutch.org>
>>>>>>      on Thu, 3 May 2018 08:55:20 -0700 writes:
> 
>      > Hi,
>      > It would be great if one of the experts could comment on the
>      > difference between Hadley's dotlength and ...length? The fact
>      > that someone bothered to implement a new primitive for that
>      > when there seems to be a very simple and straightforward R-only
>      > solution suggests that there might be some gotchas/pitfalls with
>      > the R-only solution.
> 
> Namely
> 
>> dotlength <- function(...) nargs()
> 
>> (This is subtly different from calling nargs() directly as it will
>> only count the elements in ...)
> 
>> Hadley
> 
> 
> Well,  I was the "someone".  In the past I had seen (and used myself)
> 
>     length(list(...))
> 
> and of course that was not usable.
> I knew of some substitute() / match.call() tricks [but I think
> did not know Bill's cute substitute(...()) !] at the time, but
> found them too esoteric.
> 
> Aditionally and importantly,  ...length()  and  ..elt(n)  were
> developed  "synchronously",  and the R-substitutes for ..elt()
> definitely are less trivial (I did not find one at the time), as
> Duncan's example to Bill's proposal has shown, so I had looked
> at .Primitive() solutions of both.
> 
> In hindsight I should have asked here for advice,  but may at
> the time I had been a bit frustrated by the results of some of
> my RFCs ((nothing specific in mind !))
> 
> But __if__ there's really no example where current (3.5.0 and newer)
> 
>    ...length()
> 
> differs from Hadley's  dotlength()
> I'd vert happy to replace ...length 's C based definition by
> Hadley's beautiful minimal solution.
> 
> Martin
> 
> 
>      > On 05/03/2018 08:34 AM, Hadley Wickham wrote:
>      >> On Thu, May 3, 2018 at 8:18 AM, Duncan Murdoch <murdoch.duncan at gmail.com> wrote:
>      >>> On 03/05/2018 11:01 AM, William Dunlap via R-devel wrote:
>      >>>>
>      >>>> In R-3.5.0 you can use ...length():
>      >>>> > f <- function(..., n) ...length()
>      >>>> > f(stop("one"), stop("two"), stop("three"), n=7)
>      >>>> [1] 3
>      >>>>
>      >>>> Prior to that substitute() is the way to go
>      >>>> > g <- function(..., n) length(substitute(...()))
>      >>>> > g(stop("one"), stop("two"), stop("three"), n=7)
>      >>>> [1] 3
>      >>>>
>      >>>> R-3.5.0 also has the ...elt(n) function, which returns
>      >>>> the evaluated n'th entry in ... , without evaluating the
>      >>>> other ... entries.
>      >>>> > fn <- function(..., n) ...elt(n)
>      >>>> > fn(stop("one"), 3*5, stop("three"), n=2)
>      >>>> [1] 15
>      >>>>
>      >>>> Prior to 3.5.0, eval the appropriate component of the output
>      >>>> of substitute() in the appropriate environment:
>      >>>> > gn <- function(..., n) {
>      >>>> +   nthExpr <- substitute(...())[[n]]
>      >>>> +   eval(nthExpr, envir=parent.frame())
>      >>>> + }
>      >>>> > gn(stop("one"), environment(), stop("two"), n=2)
>      >>>> <environment: R_GlobalEnv>
>      >>>>
>      >>>
>      >>> Bill, the last of these doesn't quite work, because ... can be passed down
>      >>> through a string of callers.  You don't necessarily want to evaluate it in
>      >>> the parent.frame().  For example:
>      >>>
>      >>> x <- "global"
>      >>> f <- function(...) {
>      >>> x <- "f"
>      >>> g(...)
>      >>> }
>      >>> g <- function(...) {
>      >>> firstExpr <- substitute(...())[[1]]
>      >>> c(list(...)[[1]], eval(firstExpr, envir = parent.frame()))
>      >>> }
>      >>>
>      >>> Calling g(x) correctly prints "global" twice, but calling f(x) incorrectly
>      >>> prints
>      >>>
>      >>> [1] "global" "f"
>      >>>
>      >>> You can get the first element of ... without evaluating the rest using ..1,
>      >>> but I don't know a way to do this for general n in pre-3.5.0 base R.
>      >>
>      >> If you don't mind using a package:
>      >>
>      >> # works with R 3.1 and up
>      >> library(rlang)
>      >>
>      >> x <- "global"
>      >> f <- function(...) {
>      >> x <- "f"
>      >> g(...)
>      >> }
>      >> g <- function(...) {
>      >> dots <- enquos(...)
>      >> eval_tidy(dots[[1]])
>      >> }
>      >>
>      >> f(x, stop("!"))
>      >> #> [1] "global"
>      >> g(x, stop("!"))
>      >> #> [1] "global"
>      >>
>      >> Hadley
>      >>
> 
>      > --
>      > Herv? Pag?s
> 
>      > Program in Computational Biology
>      > Division of Public Health Sciences
>      > Fred Hutchinson Cancer Research Center
>      > 1100 Fairview Ave. N, M1-B514
>      > P.O. Box 19024
>      > Seattle, WA 98109-1024
> 
>      > E-mail: hpages at fredhutch.org
>      > Phone:  (206) 667-5791
>      > Fax:    (206) 667-1319
> 
>      > ______________________________________________
>      > R-devel at r-project.org mailing list
>      > https://urldefense.proofpoint.com/v2/url?u=https-3A__stat.ethz.ch_mailman_listinfo_r-2Ddevel&d=DwIDAw&c=eRAMFD45gAfqt84VtBcfhQ&r=BK7q3XeAvimeWdGbWY_wJYbW0WYiZvSXAJJKaaPhzWA&m=BGlRjScM4h5whbLQ891iVxeMRA4PY37vwG3cnC5kuDI&s=_XZhh9pIVv0VBjUYXBgW39dss7YCGQE3XCArLMDfvDo&e=
> 

-- 
Herv? Pag?s

Program in Computational Biology
Division of Public Health Sciences
Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N, M1-B514
P.O. Box 19024
Seattle, WA 98109-1024

E-mail: hpages at fredhutch.org
Phone:  (206) 667-5791
Fax:    (206) 667-1319



[Rd] length of `...`
=?UTF-8?B?SGVydsOpIFBhZ8Oocw==?=