Skip to content

Why does NextMethod() pick up duplicate arguments in '...' if given positionally at top level?

3 messages · Duncan Murdoch, Michael Chirico

#
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
#
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:
#
Thanks Duncan! I filed [1]. I didn't have a clue how to fix it, so I
figured, why not ask an LLM [2].

It got the solution quite wrong (unless I'm just not zen enough to
understand its wisdom), but it _did_ focus my attention on the right
place. I have a patch going through CI at [3] that fixes the bug, I
just don't know what knock-on effects it might have.

[1] https://bugs.r-project.org/show_bug.cgi?id=18875
[2] https://claude.ai/share/2b702387-6aef-44ee-9e28-17c9096ce8f0
[3] https://github.com/r-devel/r-svn/pull/198
On Tue, Mar 25, 2025 at 3:30?AM Duncan Murdoch <murdoch.duncan at gmail.com> wrote: