You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
While working on the evolution vignette (#143), we (well mostly Claude 😆) verified that the two existing ways to retire a generic's name each cover only half the problem:
Plain alias (gen1 <- gen2, both exported): downstream method registrations keep working and both names dispatch (lab scenario gen-rename-alias), but callers get no deprecation signal.
Wrapper function (gen1 <- function(x, ...) { .Deprecated("gen2"); gen2(x, ...) }): callers are warned, but a wrapper is not a generic, so every downstream method(gen1, ...) <- errors and those packages can't even be installed.
Instead I think we should provide a first-class function to help do this:
# pkgA, version 2gen2:= new_generic("x")
gen1:= deprecated_generic(gen2) # exported under the old name
The returned object is a closure with class S7_deprecated_generic that:
On call: signals a classed deprecation warning (probably once per session) and delegates to gen2() with all arguments.
On registration: as_generic() (and as_external_generic()) unwrap it, so method(gen1, MyClass) <- f registers on the shared gen2.
On print/introspection: identifies itself as deprecated and names the replacement.
Bonus properties:
Mitigates Can't move generics to another package #729 for renames: a stale downstream package's deferred registration looks up the old name, finds the deprecated-generic object, and unwraps it — instead of library() failing.
Also the right endpoint for a generic moved to another package (vignette("evolution")'s move recipe): NAMESPACE re-export while alive, deprecated_generic(pkgAcore::gen) when retiring the old home.
Related: #727 is the class-side counterpart (renaming a class through an alias); #726 (graceful re-sourcing) is about the same check-vs-continue tension at method registration time.
I think the default should use .Deprecated() and but provide a callback so you can use lifecycle style if you want. Also needs to work with no existing generic to declare it's deprecated with no replacement.
While working on the evolution vignette (#143), we (well mostly Claude 😆) verified that the two existing ways to retire a generic's name each cover only half the problem:
gen1 <- gen2, both exported): downstream method registrations keep working and both names dispatch (lab scenariogen-rename-alias), but callers get no deprecation signal.gen1 <- function(x, ...) { .Deprecated("gen2"); gen2(x, ...) }): callers are warned, but a wrapper is not a generic, so every downstreammethod(gen1, ...) <-errors and those packages can't even be installed.Instead I think we should provide a first-class function to help do this:
The returned object is a closure with class
S7_deprecated_genericthat:gen2()with all arguments.as_generic()(andas_external_generic()) unwrap it, somethod(gen1, MyClass) <- fregisters on the sharedgen2.Bonus properties:
library()failing.vignette("evolution")'s move recipe): NAMESPACE re-export while alive,deprecated_generic(pkgAcore::gen)when retiring the old home.Related: #727 is the class-side counterpart (renaming a class through an alias); #726 (graceful re-sourcing) is about the same check-vs-continue tension at method registration time.
I think the default should use
.Deprecated()and but provide a callback so you can use lifecycle style if you want. Also needs to work with no existing generic to declare it's deprecated with no replacement.