Skip to content

Commit f1cfc16

Browse files
authored
Merge pull request #3491 from epage/implicit
RFC: Remove implicit features in a new edition
2 parents e49fd46 + 1db0bd7 commit f1cfc16

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

text/3491-remove-implicit-features.md

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
- Feature Name: `remove-implicit-feature`
2+
- Start Date: 2023-09-18
3+
- RFC PR: [rust-lang/rfcs#3491](https://github.com/rust-lang/rfcs/pull/3491)
4+
- Tracking Issue: [rust-lang/cargo#12826](https://github.com/rust-lang/cargo/issues/12826)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
By default, cargo will treat any optional dependency as a
10+
[feature](https://doc.rust-lang.org/cargo/reference/features.html).
11+
As of cargo 1.60, these can be disabled by declaring a feature that activates
12+
the optional dependency as `dep:<name>`
13+
(see [RFC #3143](https://rust-lang.github.io/rfcs/3143-cargo-weak-namespaced-features.html)).
14+
15+
On the next edition, cargo will stop exposing optional dependencies as features
16+
implicitly, requiring users to add `foo = ["dep:foo"]` if they still want it exposed.
17+
18+
# Motivation
19+
[motivation]: #motivation
20+
21+
While implicit features offer a low overhead way of defining features,
22+
- It is easy to overlook using `dep:` when the optional dependency is not intended to be exposed
23+
- Making it easy for crate authors to use the wrong syntax and be met with errors ([rust-lang/cargo#10125](https://github.com/rust-lang/cargo/issues/10125))
24+
- Potentially breaking people if they are later removed ([rust-lang/cargo#12687)](https://github.com/rust-lang/cargo/pull/12687))
25+
- Leading to confusing choices when `cargo add` lists features that look the same (e.g. `cargo add serde` showing `derive` and `serde_derive`)
26+
- Leading to confusing errors for callers when they reference the dependency, instead of the feature, and things don't work right
27+
- Tying feature names to dependency names is a code smell because it ties the API to the implementation
28+
- It requires people and tools to deal with this special case ([rust-lang/cargo#10543](https://github.com/rust-lang/cargo/issues/10543))
29+
- Granted, anything having to deal with old editions will still have to deal with this
30+
31+
# Guide-level explanation
32+
[guide-level-explanation]: #guide-level-explanation
33+
34+
35+
36+
Updated documentation:
37+
38+
## Optional Dependencies
39+
*(Replaces the [same section in the book](https://doc.rust-lang.org/cargo/reference/features.html#optional-dependencies))*
40+
41+
Dependencies can be marked "optional", which means they will not be compiled
42+
by default.
43+
44+
For example, let's say that our 2D image processing library uses
45+
an external package to handle GIF images. This can be expressed like this:
46+
47+
```toml
48+
[features]
49+
gif = ["dep:giffy"]
50+
51+
[dependencies]
52+
giffy = { version = "0.11.1", optional = true }
53+
```
54+
55+
This means that this dependency will only be included if the `gif`
56+
feature is enabled.
57+
58+
> **Note**: Prior to the 202X edition, features were implicitly created for
59+
> optional dependencies not referenced via `dep:`.
60+
61+
> **Note**: Another way to optionally include a dependency is to use
62+
> [platform-specific dependencies]. Instead of using features, these are
63+
> conditional based on the target platform.
64+
65+
# Reference-level explanation
66+
[reference-level-explanation]: #reference-level-explanation
67+
68+
## Existing editions
69+
70+
As is expected for edition changes, `cargo fix --edition` will add `foo = ["dep:foo"]` features as needed.
71+
Where undesired, users can remove these and switch their references to the
72+
dependency from `foo` to `dep:foo`,
73+
dealing with the [potential breaking changes](https://doc.rust-lang.org/cargo/reference/semver.html#cargo-remove-opt-dep).
74+
75+
Ideally, this will be accomplished by `cargo` emitting an allow-by-default
76+
warning when parsing a workspace member's package when an optional dependency
77+
is not referenced via `dep:` in the features
78+
([rust-lang/cargo#9088](https://github.com/rust-lang/cargo/issues/9088))
79+
using the planned warning control system
80+
([rust-lang/cargo#12235](https://github.com/rust-lang/cargo/issues/12235)).
81+
The warning will be named something like `cargo::implicit_feature` and be part
82+
of the `cargo::rust-202X-compatibility` group.
83+
84+
Suggested text:
85+
```
86+
implicit features for optional dependencies is deprecated and will be unavailable in the 202X edition.
87+
```
88+
This would be machine applicable with a suggestion to add `foo = ["dep:foo"]`. `cargo fix` would then insert this feature.
89+
90+
If that system is not ready in time, we can always hard code the change in `cargo fix`.
91+
92+
## Next edition
93+
94+
On the next edition, this warning will be a hard error.
95+
96+
Suggested text:
97+
```
98+
unused optional dependency `foo`. To use it, a feature must activate it with `dep:foo` syntax
99+
```
100+
This could be machine applicable with a suggestion to add `foo = ["dep:foo"]`.
101+
102+
## Other
103+
104+
To help users through this, `cargo add` will be updated so that `cargo add foo
105+
--optional` will create a `foo = ["dep:foo"]` if its not already referenced by
106+
another features
107+
([rust-lang/cargo#11010](https://github.com/rust-lang/cargo/issues/11010)).
108+
109+
# Drawbacks
110+
[drawbacks]: #drawbacks
111+
112+
- Some boilerplate is needed for all features, rather than just a subset
113+
- Extra ecosystem churn on the next edition update
114+
115+
# Rationale and alternatives
116+
[rationale-and-alternatives]: #rationale-and-alternatives
117+
118+
Instead of a `cargo::rust-202X-compatibility` group, we could put this in
119+
`rust-202X-compatibility` so there is one less group to enable to prepare for
120+
the next edition at the risk of user confusion over a "rust" lint controlling cargo.
121+
122+
Instead of an error, optional dependencies could be
123+
- Make optional dependencies private features ([RFC #3487](https://github.com/rust-lang/rfcs/pull/3487))
124+
- Seems like the need for this would be relatively low and be less obvious
125+
- We could still transition to this in the future
126+
- Allow access to the feature via `#[cfg(accessible)]` ([RFC #2523](https://rust-lang.github.io/rfcs/2523-cfg-path-version.html))
127+
128+
# Prior art
129+
[prior-art]: #prior-art
130+
131+
# Unresolved questions
132+
[unresolved-questions]: #unresolved-questions
133+
134+
# Future possibilities
135+
[future-possibilities]: #future-possibilities

0 commit comments

Comments
 (0)