Skip to content

Add deprecated_generic(), deprecated_class(), and deprecated_property() - #734

Open
hadley wants to merge 1 commit into
mainfrom
deprecated-helpers
Open

Add deprecated_generic(), deprecated_class(), and deprecated_property()#734
hadley wants to merge 1 commit into
mainfrom
deprecated-helpers

Conversation

@hadley

@hadleyhadley commented Jul 28, 2026

Copy link
Copy Markdown
Member

Fixes#727. Fixes#730.

This PR adds a standard way to deprecate the pieces of an S7 API — generics, classes, and properties — so that old code keeps working but warns users to update.

API

All three helpers require when (the package version when the deprecation began) and share a method argument controlling how the deprecation is signalled: "base" (the default, a .Deprecated()-style warning attributed to the user's call), "lifecycle(warn)", or "lifecycle(stop)". The lifecycle options require lifecycle as a dependency of the deprecating package.

deprecated_generic()

# renamedsummarise:= deprecated_generic(new=summarize, when="1.1.0")
# retired with no replacementshout:= new_generic("x")
shout:= deprecated_generic(old=shout, when="2.0.0")

Calling the old name warns then delegates to the target (via call rewriting, so arguments pass through lazily and unmodified). method<-, method(), method_explain(), S7_methods(), and deferred external-generic registrations all silently unwrap to the target, so downstream packages keep installing and working. This also mitigates #729 for renames: a stale downstream registration finds the deprecated object and resolves through it.

deprecated_class()

Dog:= deprecated_class(new=Pet, when="2.0.0")

Calling the constructor warns then constructs an instance of new. In every other context (as_class() is the chokepoint: method signatures, parent, property classes, unions, convert(), S7_inherits(), new_external_class() resolution) the alias is silently treated as the replacement. The no-replacement form mirrors the generic: Cat := deprecated_class(old = Cat, when = "3.0.0").

deprecated_property()

Basket:= new_class(properties=list(
size=class_double,
deprecated_property("count", new="size", when="1.5.0")
))

Generalizes the getter/setter pattern from vignette("classes-objects") (which now uses it): reading or writing the old name warns and delegates to the replacement, and the generated default means the constructor only warns when the deprecated argument is actually supplied. With no new, the property stores data itself and warns on access (construction can't warn in that case, since S7 can't distinguish a user-supplied value from the default).

new_external_class() now resolves aliases (#727)

resolve_external_class_req() no longer requires the exported object's @name/@package to match the reference, so a class renamed with a plain alias (Foo <- Bar) or a deprecated_class() keeps working for downstream packages.

Provides a standard way to deprecate parts of an S7 API while keeping old
code working:
* deprecated_generic() wraps a generic: calls warn then delegate, and
method registrations are silently redirected to the replacement.
* deprecated_class() aliases a class: the constructor warns, and every
other context (signatures, parent, property classes, external class
references) silently resolves to the replacement.
* deprecated_property() warns on read/write, delegating storage to the
replacement property.
All three require a `when` version, support deprecation without a
replacement (via `old` for generics/classes), and signal with a
.Deprecated()-style warning by default; method = "lifecycle(warn)" or
"lifecycle(stop)" uses the lifecycle package instead.
Also relaxes resolve_external_class_req() so new_external_class()
references resolve through exported aliases (plain or deprecated),
allowing classes to be renamed without breaking downstream packages.
Fixes#727. Fixes#730.
@hadley
hadley marked this pull request as ready for review July 28, 2026 21:21
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Can't deprecate generics Can't rename classes

1 participant

@hadley