Bug 15937 - callGeneric uses wrong variable scope for "..." arguments
Summary: callGeneric uses wrong variable scope for "..." arguments
Alias: None
Product: R
Classification: Unclassified
Component: S4methods (show other bugs)
Version: R 3.1.0
Hardware: x86_64/x64/amd64 (64-bit) Linux-Ubuntu
: P5 normal
Assignee: R-core
Depends on:
Reported: 2014-08-16 00:34 UTC by Ryan Thompson
Modified: 2014-08-25 07:17 UTC (History)
2 users (show)

See Also:

code to reproduce the bug (627 bytes, text/plain)
2014-08-16 00:34 UTC, Ryan Thompson

Note You need to log in before you can comment on or make changes to this bug.
Description Ryan Thompson 2014-08-16 00:34:34 UTC
Created attachment 1646 [details]
code to reproduce the bug

I've created minimal code to reproduce the test case here: https://gist.github.com/DarwinAwardWinner/f8c64c74527c2d7d94d3

It seems that when the following things all happen at once, it results in the dots argument being evaluated in the wrong scope:

1. A function is a generic with a dots argument
2. One of its methods calls another via callGeneric, passing through the dots
3. A second function calls the first one in such a way that triggers the callGeneric call.

This is hard to explain, and much easier to understand if you run the example code. But it seems like clearly wrong behavior to me.
Comment 1 John Chambers 2014-08-16 22:49:15 UTC
This seems a valid example, thanks.

The bad news is I don't see how to fix it, given the behavior of the substitute() function in R.

When callGeneric() is called with arguments, the (simple) computation is to substitute the name of the actual generic and call that function with the same arguments as were given to callGeneric(), by the construction
where ... is supposed to be the arguments to callGeneric() itself.

But if "..." is also one of the formal arguments to the generic, substitute() runs back up the call stack continuing to substitute. [this seems downright wrong but not much chance of changing it, I suspect]

In general, this seems to end up with a call that may  be inconsistent with everything.  In your example, going back one more step on the call stack would work, but AFAICS that won't work in all cases, if there's a mix of ... and other arguments.

Open to suggestions.
Comment 2 Ryan Thompson 2014-08-16 23:27:15 UTC
Well, I don't know enough about non-standard evaluation in R to suggest anything specific, but your description of the problem kind of sounds like something that might be addressed in Hadley's "lazy" package: https://github.com/hadley/lazy
Comment 3 John Chambers 2014-08-17 00:48:12 UTC
The lazy package is a bit different, and I would hesitate to incorporate the code into the base R source.

On rethinking, most conceivable examples can be handled by just evaluating all the arguments & using do.call().  This may fail in some obscure use of lazy evaluation in the method.  The corresponding fix works for the reported example.

Committed to the r-devel version in revision 66408.  (Please check it on the actual motivating example.  If it works there, I will migrate the fix to the current patched version.)