Iñaki Ucar
2019-May-14 10:50 UTC
[Rd] [R-pkg-devel] Three-argument S3method declaration does not seem to affect dispatching from inside the package.
On Tue, 14 May 2019 at 12:31, Pavel Krivitsky <pavel at uow.edu.au> wrote:> > > Note that disabling name-based dispatch implies two things: 1) the > > inability to override your method by defining gen.formula in the > > global environment, and 2) another package can break yours (i.e., > > internal calls to gen()) by registering an S3 method for gen() after > > you. > > That's a good point. > > > library(anRpackage) > > gen(a~b) > I am the S3method-declared method. > > gen.formula <- function(object, ...){message("I am the externally declared method.")} > > gen(a~b) > I am the externally declared method. > > test_me() > I am the tester. Which one will I call? > I am the function with an unfortunate name. > > In that case, I think that the least surprising behaviour would > prioritise declarations and methods "nearer" to the caller over those > "farther" from the caller (where "caller" is the caller of the generic, > not the generic itself), and, within that, give precedence to S3method > declarations over function names.The thing is that, in R, "nearer" means "the calling environment" (and then, other things). When you call test_me(), the calling environment for gen() is the package namespace. When you call gen() directly, then the calling environment is the global environment. So what happens here follows the principle of least astonishment. The issue here is that you are registering a non-standard name (.gen.formula) for that generic and then defining what would be the standard name (gen.formula) for... what purpose? IMHO, this is a bad practice and should be avoided.> That is, for a call from inside a package, the order of precedence > would be as follows: > 1. S3method() in that package's NAMESPACE. > 2. Appropriately named function in that package (exported or not). > 3. Appropriately named function in calling environment (which may be > GlobalEnv). > 4. S3method() in other loaded packages' NAMESPACEs. > 5. Appropriately named functions exported by other loaded packages' > NAMESPACEs. > > For a call from outside a package, the precedence is the same, but 1 > and 2 are not relevant. > > As far as I can tell, this is the current behaviour except for the > relative ordering of 1 and 2.Nope. Current behaviour (see details in ?UseMethod) is: "To support this, UseMethod and NextMethod search for methods in two places: in the environment in which the generic function is called, and in the registration data base for the environment in which the generic is defined". Changing this would probably break a lot of things out there. I?aki
Pavel Krivitsky
2019-May-18 21:34 UTC
[Rd] [R-pkg-devel] Three-argument S3method declaration does not seem to affect dispatching from inside the package.
Hi, Inaki, On Tue, 2019-05-14 at 12:50 +0200, I?aki Ucar wrote:> The thing is that, in R, "nearer" means "the calling environment" > (and then, other things). When you call test_me(), the calling > environment for gen() is the package namespace. When you call gen() > directly, thenthe calling environment is the global environment. So > what happens here follows the principle of least astonishment.I don't think that we disagree about which environment takes precedence. The issue is whether *within a a given environment*, registration or function naming should take precedence.> The issue here is that you are registering a non-standard name > (.gen.formula) for that generic and then defining what would be the > standard name (gen.formula) for... what purpose? IMHO, this is a bad > practice and should be avoided.The situation initially arose when I wanted to soft-deprecate calling a particular method by its full name in order to clean up the package's namespace. To use our working example, I wanted calls to gen.formula() to issue a deprecation warning, but calls to gen(formula) not to. The simplest way to do that that I could find was to create a function, say, .gen.formula() that would implement the method and declare it as the S3 export, and modify gen.formula() to issue the warning before passing on to .gen.formula(). Then, direct calls to gen.formula() would produce a warning, but gen(formula) would by pass it.> > That is, for a call from inside a package, the order of precedence > > would be as follows: > > 1. S3method() in that package's NAMESPACE. > > 2. Appropriately named function in that package (exported or > > not). > > 3. Appropriately named function in calling environment (which > > may be > > GlobalEnv). > > 4. S3method() in other loaded packages' NAMESPACEs. > > 5. Appropriately named functions exported by other loaded > > packages' > > NAMESPACEs. > > > > For a call from outside a package, the precedence is the same, but > > 1 and 2 are not relevant. > > > > As far as I can tell, this is the current behaviour except for the > > relative ordering of 1 and 2. > > Nope. Current behaviour (see details in ?UseMethod) is: > > "To support this, UseMethod and NextMethod search for methods in two > places: in the environment in which the generic function is called, > and in the registration data base for the environment in which the > generic is defined".Can you be more specific where the sequence above contradicts the current implementation (except for swapping 1 and 2)? As far as I can tell, it's just a more concrete description of what's in the documentation. Best Regards, Pavel -- Pavel Krivitsky Lecturer in Statistics National Institute of Applied Statistics Research Australia (NIASRA) School of Mathematics and Applied Statistics | Building 39C Room 154 University of Wollongong NSW 2522 Australia T +61 2 4221 3713 Web (NIASRA): http://niasra.uow.edu.au/index.html Web (Personal): http://www.krivitsky.net/research ORCID: 0000-0002-9101-3362 NOTICE: This email is intended for the addressee named and may contain confidential information. If you are not the intended recipient, please delete it and notify the sender. Please consider the environment before printing this email.
Iñaki Ucar
2019-May-19 14:59 UTC
[Rd] [R-pkg-devel] Three-argument S3method declaration does not seem to affect dispatching from inside the package.
On Sat, 18 May 2019 at 23:34, Pavel Krivitsky <pavel at uow.edu.au> wrote:> > > The issue here is that you are registering a non-standard name > > (.gen.formula) for that generic and then defining what would be the > > standard name (gen.formula) for... what purpose? IMHO, this is a bad > > practice and should be avoided. > > The situation initially arose when I wanted to soft-deprecate calling a > particular method by its full name in order to clean up the package's > namespace. > > To use our working example, I wanted calls to gen.formula() to issue a > deprecation warning, but calls to gen(formula) not to. The simplest way > to do that that I could find was to create a function, say, > .gen.formula() that would implement the method and declare it as the S3 > export, and modify gen.formula() to issue the warning before passing on > to .gen.formula(). Then, direct calls to gen.formula() would produce a > warning, but gen(formula) would by pass it.IMO the simplest way to do this is to check who the caller was: foo <- function(x) UseMethod("foo") foo.bar <- function(x) { sc <- sys.call(-1) if (is.null(sc) || sc[[1]] != "foo") .Deprecated(msg="Calling 'foo.bar' directly is deprecated") } x <- 1 class(x) <- "bar" foo(x) # silent foo.bar(x) # a warning is issued> > > That is, for a call from inside a package, the order of precedence > > > would be as follows: > > > 1. S3method() in that package's NAMESPACE. > > > 2. Appropriately named function in that package (exported or > > > not). > > > 3. Appropriately named function in calling environment (which > > > may be > > > GlobalEnv). > > > 4. S3method() in other loaded packages' NAMESPACEs. > > > 5. Appropriately named functions exported by other loaded > > > packages' > > > NAMESPACEs. > > > > > > For a call from outside a package, the precedence is the same, but > > > 1 and 2 are not relevant. > > > > > > As far as I can tell, this is the current behaviour except for the > > > relative ordering of 1 and 2. > > > > Nope. Current behaviour (see details in ?UseMethod) is: > > > > "To support this, UseMethod and NextMethod search for methods in two > > places: in the environment in which the generic function is called, > > and in the registration data base for the environment in which the > > generic is defined". > > Can you be more specific where the sequence above contradicts the > current implementation (except for swapping 1 and 2)? As far as I can > tell, it's just a more concrete description of what's in the > documentation.The description in the documentation means that point 3) in your list goes always first, which automatically implies 2) if the generic is defined in the same package. I?aki
Reasonably Related Threads
- [R-pkg-devel] Three-argument S3method declaration does not seem to affect dispatching from inside the package.
- [R-pkg-devel] Three-argument S3method declaration does not seem to affect dispatching from inside the package.
- [R-pkg-devel] Three-argument S3method declaration does not seem to affect dispatching from inside the package.
- [R-pkg-devel] Three-argument S3method declaration does not seem to affect dispatching from inside the package.
- [R-pkg-devel] Three-argument S3method declaration does not seem to affect dispatching from inside the package.