Michael Chirico
2025-Mar-25 06:12 UTC
[Rd] Why does NextMethod() pick up duplicate arguments in '...' if given positionally at top level?
Consider: foo <- function(x, y, ...) { UseMethod("foo") } foo.default <- function(x, y = 0, ...) { cat(sprintf("%s: x=%s, y=%s\n", as.character(match.call()[[1L]]), x, y)) if (...length()) str(list(...)) } foo.C <- function(x, y = 3, ...) { cat(sprintf("%s: x=%s, y=%s\n", as.character(match.call()[[1L]]), x, y)) if (...length()) str(list(...)) NextMethod("foo", x = x, y = y) } c <- structure(class = "C", 1) # 'x' winds up in ..1 foo(c) # foo.C: x=1, y=3 # foo.default: x=1, y=3 # List of 1 # $ : 'C' num 1 # empty ...! foo(x=c) # foo.C: x=1, y=3 # foo.default: x=1, y=3 # now both x is ..1, y is ..2 foo(c, 4) # foo.C: x=1, y=4 # foo.default: x=1, y=4 # List of 2 # $ : 'C' num 1 # $ : num 4 # perhaps predictably, ...length()==0 foo(x=c, y=4) # foo.C: x=1, y=4 # foo.default: x=1, y=4 I've tried re-reading ?NextMethod a few times as well as R-lang [1] & can't make heads or tails of this. I've also come across related 2012 (!) thread [2] and tangentially-related bug [3]. Is this intended behavior? If so, might I reiterate Henrik's long-ago request for better documentation of how to work around this? For some added context, where I actually encountered this, my S3 method is mainly written to overwrite the defaults of a parent class's method. Mike C [1] https://cran.r-project.org/doc/manuals/r-devel/R-lang.html#NextMethod [2] https://stat.ethz.ch/pipermail/r-devel/2012-October/065016.html [3] https://bugs.r-project.org/show_bug.cgi?id=15654
Duncan Murdoch
2025-Mar-25 10:30 UTC
[Rd] Why does NextMethod() pick up duplicate arguments in '...' if given positionally at top level?
I don't think there's any valid reason for this behaviour, i.e. it's a bug. For those who haven't read closely, the bug is that in the `foo(c)` call, within foo.default() the value of `c` is bound to both x and to the first element of ... . The 2012 thread you link to started with a slightly different setup and arguments were made by Simon that the behaviour is documented, but the final message in the thread is about the same bug as here. I think the bug report 15654 is about the first setup, not the current one. So what I'd suggest you do is report this example in a new bug report, and if you have the energy (seems nobody else does!), track down where the duplication happens, and include a patch to fix it. If you do attempt that, you'll probably learn enough about NextMethod to decide whether to follow the suggestion in 15654, and could maybe submit a patch for that, too. Duncan Murdoch On 2025-03-25 2:12 a.m., Michael Chirico wrote:> Consider: > > foo <- function(x, y, ...) { > UseMethod("foo") > } > > foo.default <- function(x, y = 0, ...) { > cat(sprintf("%s: x=%s, y=%s\n", as.character(match.call()[[1L]]), x, y)) > if (...length()) str(list(...)) > } > > foo.C <- function(x, y = 3, ...) { > cat(sprintf("%s: x=%s, y=%s\n", as.character(match.call()[[1L]]), x, y)) > if (...length()) str(list(...)) > NextMethod("foo", x = x, y = y) > } > > c <- structure(class = "C", 1) > > # 'x' winds up in ..1 > foo(c) > # foo.C: x=1, y=3 > # foo.default: x=1, y=3 > # List of 1 > # $ : 'C' num 1 > > # empty ...! > foo(x=c) > # foo.C: x=1, y=3 > # foo.default: x=1, y=3 > > # now both x is ..1, y is ..2 > foo(c, 4) > # foo.C: x=1, y=4 > # foo.default: x=1, y=4 > # List of 2 > # $ : 'C' num 1 > # $ : num 4 > > # perhaps predictably, ...length()==0 > foo(x=c, y=4) > # foo.C: x=1, y=4 > # foo.default: x=1, y=4 > > I've tried re-reading ?NextMethod a few times as well as R-lang [1] & > can't make heads or tails of this. I've also come across related 2012 > (!) thread [2] and tangentially-related bug [3]. > > Is this intended behavior? If so, might I reiterate Henrik's long-ago > request for better documentation of how to work around this? > > For some added context, where I actually encountered this, my S3 > method is mainly written to overwrite the defaults of a parent class's > method. > > Mike C > > [1] https://cran.r-project.org/doc/manuals/r-devel/R-lang.html#NextMethod > [2] https://stat.ethz.ch/pipermail/r-devel/2012-October/065016.html > [3] https://bugs.r-project.org/show_bug.cgi?id=15654 > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel
Possibly Parallel Threads
- Why does NextMethod() pick up duplicate arguments in '...' if given positionally at top level?
- NextMethod() example from S Programming by Venables and Ripley (page 78)
- Do *not* pass '...' to NextMethod() - it'll do it for you; missing documentation, a bug or just me?
- How to modify dots and dispatch NextMethod
- How to modify dots and dispatch NextMethod