Thanks to all who replied and provided input. @Duncan: Yes, of course there is the note about masking. In my experience, many people won't understand what this means, what the consequences are, and that pkgA::foo(x) and pkgB::foo(x) are workarounds. And yes, pkgA importing the foo() generic from pkgB or vice-versa is an obvious solution.
@Bert: Related to the suggestion that one package could import the generic from the other, you raise an important point. This in essence adds a whole package as a dependency for these two lines of code: foo <- function(x, ...) UseMethod("foo") And let's say pkgA imports this from pkgB and pkgB depends on 10 other packages? Does this mean that pkgA has now added 11 packages as dependencies for importing 2 lines of code? If so, that seems quite undesirable to me. @Neal: A separate package with generic functions that pkgA and pkgB could import is an interesting suggestion, thanks! @Tom: I might need some time to process what you are suggesting. What I am really hoping for (and not sure if your approach can handle this) is that the following works regardless of the order in which pkgA and pkgB are loaded: x <- 1:4 class(x) <- "A" foo(x) class(x) <- "B" foo(x) Again, that used to be the case in R 3.6.3, but not anymore in 4.0.x. Best, Wolfgang >-----Original Message----- >From: R-package-devel [mailto:r-package-devel-boun...@r-project.org] On >Behalf Of Bert Gunter >Sent: Tuesday, 23 June, 2020 4:55 >To: luke-tier...@uiowa.edu >Cc: r-package-devel@r-project.org >Subject: Re: [R-pkg-devel] [External] Re: Two packages with the same generic >function > >OK. Thanks. > >Bert Gunter > >On Mon, Jun 22, 2020 at 7:51 PM <luke-tier...@uiowa.edu> wrote: > >> On Tue, 23 Jun 2020, Bert Gunter wrote: >> >> > "Users don't get warned about overriding names in packages they've >> > loaded, because that would just be irritating." >> >> All Duncan is saying is that you don't get a notification if you do >> >> mean <- log >> >> in the interpreter. If you attach a package that does this you would >> get a notification (or an error if you configure your conflict >> resolution options appropriately). >> >> Best, >> >> luke >> >> > >> > Is that also true if the package or generic is imported by another that >> > they load; or is a dependency of a package they load? If so, I would not >> > call it "just irritating" because if silent, how would they know? >> > >> > >> > Bert Gunter >> > >> > "The trouble with having an open mind is that people keep coming along >> and >> > sticking things into it." >> > -- Opus (aka Berkeley Breathed in his "Bloom County" comic strip ) >> > >> > >> > On Mon, Jun 22, 2020 at 5:58 PM Mark Leeds <marklee...@gmail.com> wrote: >> > >> >> Hi Duncan: I maintain dynlm and your example is the exact reason I've >> been >> >> getting emails from people regarding >> >> it not working correctly. I've been telling them to load dplyr by using >> >> >> >> library(dplyr, exclude = c("filter", "lag")) >> >> >> >> On Mon, Jun 22, 2020 at 7:57 PM Duncan Murdoch < >> murdoch.dun...@gmail.com> >> >> wrote: >> >> >> >>> On 22/06/2020 3:48 p.m., Tom Wainwright wrote: >> >>>> Yet another alternative is simply to prevent your second package from >> >>>> overriding the previously defined generic. The basic problem is the >> >> ease >> >>>> with which R allows overriding prior generic definitions (one of >those >> >>> bits >> >>>> of bad behavior we in the USA used to call "a Bozo No-No"), which >> hides >> >>> all >> >>>> the previous methods, as demonstrated by the following code: >> >>>> >> >>>>> plot(1:3) >> >>>>>> plot <- function(x, ...) UseMethod("plot") >> >>>>>> plot(1:3) >> >>>>> Error in UseMethod("plot") : >> >>>>> no applicable method for 'plot' applied to an object of class >> >>>>> "c('integer', 'numeric')" >> >>>>>> rm(plot) >> >>>>>> plot(1:3) >> >>>> >> >>>> (Despite Murdoch's suggestion that overriding the generic SHOULD >issue >> >> a >> >>>> warning, it doesn't seem to in R 4.0.1.) >> >>> >> >>> Sure it does, if pkgA and pkgB both export the same name, then you get >> a >> >>> warning when you attach the second one. For example, >> >>> >> >>> > library(MASS) >> >>> > library(dplyr) >> >>> >> >>> Attaching package: ‘dplyr’ >> >>> >> >>> The following object is masked from ‘package:MASS’: >> >>> >> >>> select >> >>> >> >>> The following objects are masked from ‘package:stats’: >> >>> >> >>> filter, lag >> >>> >> >>> The following objects are masked from ‘package:base’: >> >>> >> >>> intersect, setdiff, setequal, union >> >>> >> >>> Users don't get warned about overriding names in packages they've >> >>> loaded, because that would just be irritating. >> >>> >> >>> Duncan Murdoch >> >>>> >> >>>> So, we might try protecting the generic definitions of "foo" in both >> >>>> packages by enclosing them in something like: >> >>>> >> >>>> tryCatch(invisible(methods("foo")), error = {foo <- function(x,...) >> >>>>> UseMethod("foo")}, finally=NULL) >> >>>> >> >>>> >> >>>> There's probably a more elegant way to accomplish this. This relies >on >> >>>> "methods" returning an error if "foo" has no defined methods, so it >is >> >>> not >> >>>> redefined if their are previous methods. I haven't had time to try >> this >> >>> in >> >>>> the two-package example, but it might work, although I'm not sure how >> >> to >> >>>> handle the Namespace declarations. >> >>>> >> >>>> Tom Wainwright >> >>>> >> >>>> On Mon, Jun 22, 2020 at 10:41 AM Bert Gunter <bgunter.4...@gmail.com> >> >>> wrote: >> >>>> >> >>>>> ... >> >>>>> and just to add to the query, assume the author of pkg B did (does) >> >> not >> >>>>> know of pkg A and so, for example, could (did) not import any of pkg >> >> A's >> >>>>> content into B. Given that there are at the moment ~20,000 packages >> >> out >> >>>>> there, this does not seem to be an unreasonable assumption. One may >> >> even >> >>>>> further assume that the user may not know that (s)he has package B >> >>> loaded, >> >>>>> as it may be a dependency of another package that (s)he uses. I >> >>> certainly >> >>>>> don't keep track of all the dependencies of packages I use. >> >>>>> >> >>>>> Under these assumptions, is there any more convenient alternative to >> >>>>> Wolfgang's pkgA:foo(x) explicit call under such assumptions? If pkgA >> >>> has a >> >>>>> long name, what might one do? >> >>>>> >> >>>>> Bert Gunter >> >>>>> >> >>>>> "The trouble with having an open mind is that people keep coming >> along >> >>> and >> >>>>> sticking things into it." >> >>>>> -- Opus (aka Berkeley Breathed in his "Bloom County" comic strip ) >> >>>>> >> >>>>> >> >>>>> On Mon, Jun 22, 2020 at 10:00 AM Viechtbauer, Wolfgang (SP) < >> >>>>> wolfgang.viechtba...@maastrichtuniversity.nl> wrote: >> >>>>> >> >>>>>> Hi All, >> >>>>>> >> >>>>>> Let's say there are two packages pkgA and pkgB, both of which have >a >> >>>>>> generic function >> >>>>>> >> >>>>>> foo <- function(x, ...) >> >>>>>> UseMethod("foo") >> >>>>>> >> >>>>>> and pkgA has a method for objects of class "A": >> >>>>>> >> >>>>>> foo.A <- function(x, ...) >> >>>>>> print(x) >> >>>>>> >> >>>>>> and pkgB has a method for objects of class "B": >> >>>>>> >> >>>>>> foo.B <- function(x, ...) >> >>>>>> plot(x) >> >>>>>> >> >>>>>> Both packages export foo and their method and declare their >> >> respective >> >>> S3 >> >>>>>> methods, so: >> >>>>>> >> >>>>>> export(foo) >> >>>>>> export(foo.A) >> >>>>>> S3method(foo, A) >> >>>>>> >> >>>>>> in NAMESPACE of pkgA and >> >>>>>> >> >>>>>> export(foo) >> >>>>>> export(foo.B) >> >>>>>> S3method(foo, B) >> >>>>>> >> >>>>>> in NAMESPACE of pkgB. >> >>>>>> >> >>>>>> If a user loads pkgA first and then pkgB, this fails: >> >>>>>> >> >>>>>> library(pkgA) >> >>>>>> library(pkgB) >> >>>>>> x <- 1:4 >> >>>>>> class(x) <- "A" >> >>>>>> foo(x) >> >>>>>> >> >>>>>> Error in UseMethod("foo") : >> >>>>>> no applicable method for 'foo' applied to an object of class "A" >> >>>>>> >> >>>>>> and vice-versa. Of course, pkgA::foo(x) works. Aside from pkgA >> >>> importing >> >>>>>> foo() or vice-versa, is there some other clever way to make this >> >> work? >> >>> In >> >>>>>> earlier versions of R (at least in 3.6.3), this used to work (i.e., >> >> the >> >>>>>> generic foo() from pkgB would find method foo.A() and vice-versa), >> >> but >> >>>>> not >> >>>>>> since 4.0.0. >> >>>>>> >> >>>>>> Best, >> >>>>>> Wolfgang ______________________________________________ R-package-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-package-devel