-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
@deprecated()
builtin
#22822
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Can't wait for when we deprecate the |
Is there merit in requiring the author to provide a string or alternative symbol to steer users in the right direction? Is a comment on the same line enough? |
i think the rejection of #3320 and the demonstration of the userspace solution shows that this would fit much better as a standard library module or 3rd party package, than as a builtin |
Pros:
Cons:
My conclusion: Due to the virality of -fno-deprecated and the fundamental change to compile flags I think this should not be added. Maybe we add it but don't ever generate errors for it just so tooling/linters can reliably detect it. |
So maybe implement this as a std function
It should definitely take a comptime string as an argument. This would make the message more explicit than a comment, which can easily get overlooked. Something like this should work:
Maybe make this behavior configurable in the |
As proposed, Speaking purely in the context of As much as I hate the term "code smell" it's also important to realize that using a deprecated API is a code smell, not a bug; a questionable pattern in your code that you should probably address, but not something that should necessarily break your build until you fix it. Any solution to the problem with status quo deprecations should focus on addressing the question "how can we let users know that they are using a deprecated API?" before it tries to go for "how do we prevent users from using a deprecated API?". If there was some static analyzer or linter, either provided by a third-party or built into the |
Accepted, with adjustments:
In other words, maintainers by default cannot make the mistake of calling into deprecated API, however, the dependency tree by default will not fail in "other people's code" due to deprecations. To those who think this is the same thing as "sloppy mode": whereas sloppy mode would create two factions in the ecosystem who each prefer a different dialect of Zig, nobody wants to be using deprecated code. Programmers will naturally steer clear of any packages that require |
to clarify, you're saying the default should be that |
Yes Andrew is changing the default behavior. |
One pain point with deprecation for library authors is remembering when to turn a value into a compile error. Release schedules can be far apart, with deprecation being applied to many APIs over the course of months. Should an additional parameter fn deprecated(value: anytype, comptime until: []const u8) @TypeOf(value) {} For example: pub const sleep = @deprecated(std.Thread.sleep, "0.16.0"); Library authors would put the semantic version of when the value should be removed. And then when the build system attempts a build of the library with semantic version greater than or equal to "0.16.0" it would result in a compile error for the author. Edit: No, this is already possible in user space with |
How well will this play with #8284? Under MVS, if I directly depend on Package A version 1.4, but I also depend on Package B which in turn depends on Package A version 1.2, the build system will pick version 1.4 of Package A. If Package A has marked APIs with (Semver specifies that "minor version [...] MUST be incremented if any public API functionality is marked as deprecated". Deprecations are not considered backward-incompatible and don't require a major version bump.)
For third-party libraries, this may be true, but for At that point, the value of deprecation notices in |
Since the meaning of |
Ah, now that's a delightfully productive question. Note that this case still fits the pattern that the project built fine with So it is still satisfying this use case:
However, I'm going to backtrack a little bit, because it is still a bit of a problem in the sense that the purpose of deprecation, as pointed out via the semver quote, is to have a grace period in which the code continues to compile by default. The thing that makes me willing to backtrack here is considering the fact that the deprecated API can simply be removed when it is time for it to be a compile error, and the purpose of tooling-aware deprecation, then, is specifically for avoiding compilation errors while providing an upgrade path. Anyway, here's the adjusted plan:
|
In my mind, it would be better to have a type of compile error, like the logging levels we have in loggers. |
Ah yes, lets call it a "warning" 🙃
To me this feels just like a distinction without a difference - why would I want to be using "sloppy" code either? Weakening Zig's stance on warnings specifically just for |
What happens when a library uses its own deprecated API's? For example, the standard library deprecates
In this scenario, a library author may have a significant number of tests that call deprecated code. If the library author wants to keep these tests, they will need a way to run them without a compile error. |
The current implementation in kristoff's PR would make this a compile error, unless compiled with
You can compile and run them with |
"Patch Awareness" is a "Spotty Game"; the concept of a tool acknowledging, from within, that it is versioned and patched. This, on its own, can only make sense in monolithic sensibilities. |
If zig is to prioritize It is true that a library author could do a maneuver like this to avoid the problem: (as mentioned by kristoff-it in this stream) pub fn sleep() void {
@deprecated()
sleepDeprecated()
}
fn sleepDeprecated() void {
...
}
where the library author now switches to using sleepDeprecated internally. But I see this as added friction for maintaining deprecated APIs. Maintaining code through deprecation cycles is one of the more difficult problems (just look at LLVM's API regressions that Zig must deal with). Why should Zig make this harder? This still has the following problems:
And has the following pros:
This begs the question of "what is deprecated code":
I view "deprecated" as still mandating maintenance, up until the next major release. |
i dont think those definitions are mutually exclusive. if code is marked deprecated, it should be moved off of immediately (even internally) as it is pending imminent deletion next release cycle and the only code calling it should be its tests. |
As it stands now, if a library author must test their own deprecated code, they will need a bash script to invoke the zig compiler twice, for the entirety of the rest of their release cycle (release cycles can be ~years). zig build -fallow-deprecated test-all-my-deprecated-stuff
zig build test-but-dont-test-all-my-deprecated-stuff |
If I understand the concern of testing deprecated functions correctly, Then we could have another flag to allow tests using this mechanism (otherwise we error). |
if it's not a nail, don't hit it with a hammer |
landed in dea72d1 |
Reverted in 6b6c1b1 |
Hi, I'm tinkering around a proposal that aim to solve this issue and many others (distinct types, comptime interface specification, ATS-inspired linear type to track resource usage and cleanup, ...) It's an annotation system for Zig which would allow, among other things, to add constraints, like the ones required by the compiler, yet implemented in user land. These would be created at comptime like Example for the current issue: const deprecated = @import("std").annotations.deprecated;
#deprecated(.{ .message = "use `bar` instead", .strict = true })
pub fn foo() T {
// ...
} With #allowDeprecated(.{ .foo }) // apply to the current container/scope
// Or in an expression, annotations are use as a pre-fix operator
const baz = if (a_build_constant) #useDeprecated foo() else bar(); Since the annotation system would allow the build script (and external tools) to scan the code for specific conditions, It would thus be possible to forbid the use of deprecated api even if This is just an exergue of the desired capabilities concerning this issue, I will provide a more in-deep proposal of the feature at a future time. |
Motivation
It's already an established pattern in the Zig ecosystem to deprecate declarations first via a doc comment, and after a while by turning the old decl into a
@compileError
once the deprecation "grace period" is over, to then finally delete the decl altogether after some more time.Currently a user that is interested in discovering early which APIs are being deprecated must grep the codebase for the word, find the decl the comment refers to, and figure out if and where its being used (directly or not) in the codebase.
Conversely, a library author that wants to maintain backwards compatibility (i.e. avoid a major version bump for a v1 package) will not want to set deprecated decls to
@compileError
as that would be a compatibility breakage, never giving users an opportunity to leverage compile errors to migrate their API usage.It is possible today to implement a better solution entirely in userland:
Running
zig build -Ddeprecated
will turn deprecated decls in compile errors giving both a nice compiler-driven upgrade experience to users, while letting library authors maintain backwards compatibility.This pattern seems so useful that might be worth enshrining it as a standardized practice.
Proposal
Introduce a
@deprecated()
builtin and a new-fdeprecated
compiler flag to be used like so (this is a contrived example to showcase the workflow):A less contrived example would be the current deprecation of
std.time.sleep
in the Zig standard library:A second example: using
@deprecated
in a function body:Lastly, since
@deprecated
conveys intent more precisely, tooling like LSPs and linters could offer diagnostics about deprecation automatically to the user in a more streamlined fashion than with the full userland solution.A branch with
@deprecated
implemented can be found here: https://github.com/kristoff-it/zig/tree/deprecated-proposal (diff)The text was updated successfully, but these errors were encountered: