Skip to content
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

Allow requiring "at least one feature" #3347

Closed

Conversation

Ericson2314
Copy link
Contributor

Allow packages to require that dependencies on them must specify at least one feature (the default feature counts). This avoids backwards compatibility problems with default-features = false.

Rendered

This is a well-known problem. See just-rejected #3283, and my previous retracted #3146.

Depending on a
```toml
[package]
at-least-one-feature = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if this could provide a way for existing crates to move over to the new system without breaking compatibility. Perhaps add a no-feature-selected = "feature" key that allows to specify the single feature that is activated when no others are?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it breaks compatibility. Because the solver knows to reject plans where the no-feature dep is mis-resovled, there are no issues. Not all downstream uses can upgrade, but all that can will.

In general I think it's good to think of version bumps as the residual of thing that the plan solver doesn't already know how to detect. Bumping a version bound is saying "sorry there is a problem I don't know how to directly say what it is, so I am going to insert this barrier instead".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it breaks compatibility. Because the solver knows to reject plans where the no-feature dep is mis-resovled, there are no issues. Not all downstream uses can upgrade, but all that can will.

I don't exactly understand your language here. Do you mean that cargo will not update a crate's dependency to a version with at-least-one-feature = true, if the depending (not dependent) crate does not specify a feature for the dependency?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly! Thanks for saying that more clearly :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That still sounds like a breaking change upgrade, even if you are protecting people from doing the upgrade.

Copy link
Contributor Author

@Ericson2314 Ericson2314 Nov 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Periodically trying to address concerns in the comments and then opening new threads I think is a good way to keep the conversation manual. Perhaps my "at-least-one-feature = true is not a breaking change" explanation is all wrong, but I think the first-order problem is the RFC originally neglected to discuss the issue at all. Now at is at least discussed, and so problems with that discussion (and I think it's better to poke holes in the RFC version than the version in the comments) are to me follow-up concerns.

All that said, if you still rather continue the conversation OK I will accept it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, the topic is breaking changes and spreading that out across multiple threads can make that harder to follow.

Copy link
Contributor Author

@Ericson2314 Ericson2314 Nov 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK Then, I'll keep it here.

And I don't think MSRV is an appropriate precedence. That is dealing with the build environment while this is dealing with the API.

I went with MSRV because it is an example of something we used to not have, so it is nice to illustrate the point about "residual" breakage. But it not the only option. (Also once rust-lang/cargo#9930 is added I don't think the "build environment" argument makes sense. Version bounds (only a lower bound because we assume there is no breaking changes in rustc) that effect version solving are bona fide dependencies, are they not?)

Is increasing a dependency bound by a narrow version a breaking change? I think the answer is also "no". Anyone stuck on the old version (private deps make this a bit harder to imagine, but public deps reveal it) will be unable to upgrade, but no breakage will occur.

Moreover, we can call this a breaking change, and that a breaking change, but does anyone benefit from bumping the version number? No. Those that already couldn't upgrade still can't. And those that previously could upgrade now also can't. "breaking" nomenclature aside, the practical difference is simply to rule at more perfectly good build plans.


See what I wrote in #3347 (comment). I think one thing worth taking from @tbu-'s RFC's is basically a one-off migration/ret-conning of default-features = false. Then we side-step is controversy entirely. The restriction in this PR ensures that the "one off" approach is sufficient --- since going forward there won't be new default-features = false users we don't have to worry about that cropping up again.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MSRV is a very different case that, just because we want to improve the experience for it, does not mean we take it as a license to do similar elsewhere.

but no breakage will occur.

does anyone benefit from bumping the version number

I would consider it a breaking change if a crate switched from foo = "1.0" to foo = "1.0;<1.3" which is effectively what we are talking about here.

This doesn't just affect "really old" crates where we can assume no one should upgrade any dependency. People upgrade dependencies piece meal. Some times they have a reason to hold back.

As I pointed out elsewhere, its not just a matter of gracefully being blocked from upgrade this dependency but being blocked from upgrading the dependency anywhere in the dependency tree. I can't depend on an unrelated crate that needs a newer version of the crate that made the switch over.

Incorporating my idea elsewhere to encourage people to use this feature via cargo new defaults and edition defaults at least improves this by moving this away from a "only enabled once someone needs it" to "its enabled defensively".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorporating my idea elsewhere to encourage people to use this feature via cargo new defaults and edition defaults at least improves this by moving this away from a "only enabled once someone needs it" to "its enabled defensively".

Yeah I do like that part, to be clear.

@tbu-
Copy link
Contributor

tbu- commented Nov 11, 2022

This looks really nice and simple, thanks for coming up with that. :)

@tbu-
Copy link
Contributor

tbu- commented Nov 12, 2022

Thinking about it some more, I think that this solution might not be too practical.

Say e.g. we're talking about seanmonstar/warp#968. warp currently ships http2 support by default. This means that in order to be able to ship a version without http2, all current features must depend on http2. This means creating new websocket-without-http2, tls-without-http2, compression-without-http2, compression-brotli-without-http2, compression-gzip-without-http2 features in order for other crates to depend on them without pulling in http2 support.

In this scenario (if I understand your proposal correctly and if I have found the best possible way to upgrade), the solution with this RFC seems impractical.

text/0000-at-least-one-feature.md Outdated Show resolved Hide resolved
text/0000-at-least-one-feature.md Show resolved Hide resolved
text/0000-at-least-one-feature.md Outdated Show resolved Hide resolved
@ogoffart
Copy link

I am also one person who really think such a way is really important for crates that wishes to keep compatibility for various reason.
(I've explained my motivation and a work-around in https://slint-ui.com/blog/rust-adding-default-cargo-feature.html )
So thanks for working on this 👏

In my opinion, this RFC is a is bit too simple (for reason explained in #3347 (comment) ). And I agree that #3283 and #3146 are a bit too complex.

I think the option to allow to specify "negative" feature would be a great change for simplicity for the users. But it can only work if nobody can do default-features=false for that crate. There might be solution there suggested in rust-lang/cargo#3126

Another idea would be to have a simplified version of #3146 without complex operators

[compat-features]
"1.4" = ["std"]

Which means that if someone selected that create with a specified version less or equal to "1.4", they get the "std" feature.

@epage
Copy link
Contributor

epage commented Nov 12, 2022

Another idea would be to have a simplified version of #3146 without complex operators

[compat-features]
"1.4" = ["std"]

Which means that if someone selected that create with a specified version less or equal to "1.4", they get the "std" feature.

  • We need to keep in mind version requirements vs versions. This shows a version requirement but doesn't work with all version requirements
  • Whether version requirements or versions, unassisted updates would break builds which is a new semantic I do not think we want.

@Ericson2314
Copy link
Contributor Author

Ericson2314 commented Nov 12, 2022

@tbu- That is true, the names to get shittier over time, I forgot to include that in drawbacks, sorry.

I am not going to lie, I kind of intentionally worse-is-bettered myself with this versus my original feature migrations. But I think that OK. This gets us out of the jam with very little effort, and once people notice the bad names in practice, then we can better advocate for something to deal with that.

Basically I think the hierarchy of needs compels us to start here.

(I'll add this to the proposal.)

@epage
Copy link
Contributor

epage commented Nov 12, 2022

@Ericson2314

I am not going to lie, I kind of intentionally worse-is-bettered myself with this versus my original feature migrations. But I think that OK. This gets us out of the jam with very little effort, and once people notice the bad names in practice, then we can better advocate for something to deal with that.

  1. If you make the barrier too high, people won't use it
  2. This requires violating semantics. When moving existing functionality to a feature, it requires adding that feature to all other features even if they do not semantically make sense. While theoretically, you can say that those features implied it anyways, that is not the model users will be taking.

@tbu-
Copy link
Contributor

tbu- commented Nov 12, 2022

  • If you make the barrier too high, people won't use it

AFAIUI, the proposal at rust-lang/cargo#3126 (comment) makes some transitions impossible instead of just impractical. I.e. if that would make the barrier too high, people can't use it.

@Ericson2314
Copy link
Contributor Author

@ogoffart Feature migrations and negative features are now discussed in the alternatives section at decent length.

@Ericson2314
Copy link
Contributor Author

Ericson2314 commented Nov 12, 2022

@epage

If you make the barrier too high, people won't use it

The barrier is strictly less high than today. Forcing a breaking change is a serious nuisance. Bad names are already necessary, just insufficient to address the default-features = false case.

This requires violating semantics.

Again this is already a requirement today for splitting features not a new issue, and I think names are only human-meaningful and so "violating semantics" is hyperbole. I prefer to keep my alpha-renaming hat on: names don't deeply matter.

Or rather, in the long term I think migrations / namespacing / whatever --- an extra layer of indirection --- is the only solution to keeping names good. Everything else feels like an awkward middle ground (I still think negative features is a terrible UX because there is no alternative to additive feature semantics).

restriction.

The main difference is that `default-features = false` is ret-conned as a feature to allow for existing users.
That can be thought of from the perspective of this RFC as a "one-off" feature migration to get reverse dependencies predating the use of `at-least-one-feature = true` on to a feature so they retroactively abide by the "at least one feature" rule.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tbu- I think you might be on to something :)

Prioritizing this single feature migration before the others complete side-steps the "is at-least-one-feature = true a breaking change?" problem, by giving default-features = false users an on-ramp to the brave new world.

What do you think @epage? If anyone wants to throw out some syntax I am happy to make this part the RFC. There could be a mini-default feature that handles the default-features = false for example, default's little sibling.

@epage in rust-lang/cargo#3126 proposed deprecating default-features = <bool> and I think that is a good idea too. I will expand the "future work" section" to discuss this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with default-features = false implying a feature when [] but not when ["base"] is that those are very unclear / confusing semantics.

However, I think we can combine this proposal with negative features and come up with something that might resolve problems with both.

First, we need to step back and talk about the two main uses for default-features = false

  • As a clap user, there are a lot of default policies to provide a good experience. People usually remove them piece meal in their applications (negative features)
  • As the author of clap-verbosity-flag, I do not want to enable any clap features but the minimum (default-features = false)

Negative features helps with one, this proposal helps with another.

What if we mixed

  • package.at-least-one-feature = true
  • default-features = false migrations
  • Negative features

The pieces

  • Add package.empty-features field, defaulted to true
    • Yeah, I'm mixing in bike shedding over the name
    • cargo new will write populate the manifest with package.empty-features = false
    • On the next edition, we change the default to package.empty-features = false
  • Allow soft requirements on features: the feature ends with ?.
    • Features required with a ? can be removed when resolving the list of features associated with a specific dependency. Much like default-features = false, this does not conflict with other dependencies that use the default feature
    • Dependent features without ? are hard errors (or maybe disabled?)
      • Errors allow adding ? without a breaking change
    • Note: you can remove features from anywhere, not just default
  • On a new edition, we remove default-features field in favor of default feature
    • We treat no-default-features as special feature for a onetime migration from package.empty-features = true to package.empty-features = false without a breaking change
    • All features that no-default-features requires will have to use ?
    • Note: we'd need to check if no-default-features is safe to add semantic meaning to
    • Command-line behavior is unchanged

We now have a way to add the http2 feature to warp without adding a bunch of without-http2 features

We can migrate to this without a breaking change. Note that I consider this an optional requirement. So long as we move people to using this for new crates and enough crates are not 1.0-forever, we might be able to get away with a breaking change.

People can choose to disable everything or disable piece meal.

I expect there are still problems with this but I'm intrigued with the vague idea of aligning these proposals.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with default-features = false implying a feature when [] but not when ["base"] is that those are very unclear / confusing semantics.

Agreed. In fact it is downright wrong, because old ["base"] feature lists still also need the migration. I was not clear but any one-off attempt at default-features = false migrations will also need to distinguish between old and new dependencies.

Still reading the rest.

Copy link
Contributor Author

@Ericson2314 Ericson2314 Nov 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm mixing in bike shedding over the name

Sure, I don't care about the name. I'll just go change it. edit done in bfc3105

Copy link
Contributor Author

@Ericson2314 Ericson2314 Nov 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@epage So I agree that it might possibly be convenient for end executable offers to opt-out of a few clap features. But I still l find it very degenerate for reusable libraries to express anti-dependencies. I think the only proper way to write a reusable library is to stick to purely additive features --- say what you need, don't waste text on what you don't need.

I think the clap-verbosity-flag use-case corresponds to my "reusable library" use-case? But the foo-without-http2 problem effects reusable libraries too.

Thus when you write

Negative features helps with one, this proposal helps with another.

I would like that but it doesn't seem quite true? We have two solutions and two use-cases, but they don't work in isolation (one solution per use-case).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My discussion on the use cases (whether to focus on negative features or disabling default features) is on the dependent side (a binary using clap, a library that integrates with clap). These would be starting points for thinking. This does not mean they are mutually exclusive, two features tacked on for different cases, but two intertwined features that overall enhance each other. Like I said, warp can add its http2 feature and an warp-integration library might use feature negation but that is fine.

To put it another way, the feature migration feature would be moving away from specifically trying to solve default features to being a general feature that also enhances this one, removing rough edges.

Some of this idea of ? feature requirements stems from @djc's comments about gentoo though I don't know if the exact idea I mentioned exists in gentoo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ? mentioned there is a bit unclear, but it is still "additive". It seems to boil down to adding extra dependencies to conjunctions of features (enabling foo and foo and bar also enables baz). I don't see what that has to do with negative dependencies.

Like I said, warp can add its http2

But that only works without the "odd named features" if we force all downstream deps to use negative feature "requests" to avoid http2. If I am writing a downstream library, a nice nugget not a big "integrationy" one for sake of argument, I don't want to use negative dependencies. I want to just regularly "additively" depend on just the parts of warp I need, and I don't want to waste any mental effort or keystrokes on features I don't care.

I don't see two intertwined features, I see distasteful negative reasoning as a cure for odd feature names that is worse than the disease. If some other use-case wants negative features I would still think they are mistaken (X Y problem), but moreover I see it bleeding into this problem when it should be orthogonal.

This proposal adds a new notion of a "feature base", which aims to essential provide more `default-features = false` options rather than just one forever.
`default-features = false` is ret-conned as the first feature base.

My view is that that RFC is pretty close to being this one in disguise.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me this RFC seems like just a special case of RFC 3283. Specifically, the case where the set of base features includes all available features. And because it is just one special case, it has problems that 3283 didn't have, notably the problems described in "bad names over time".

Personally, I'd rather see a more general solution where you specify multiple sets of features where at least one must be included, so you could for example say you need at least one of "http1" and "http2" and at least one of a set of features for TLS support (rustls, native-tls, etc.).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I don't think this is special case to that. Consider if default and default-features = <bool> and all that didn't exist. This would still be solution.

It is probably best to imagine 3 parts:

  1. This to fix the original problem.
  2. Some deprecation cycle with editions to get rid of default-features = <bool>
  3. Some namespacing / indirection so we can use good names forever.

Each builds on the last, but the former steps stand alone.

Remember Rust itself has the same name issue! If you end up making a new version function which deserves the name more than the old version and don't want to make a breaking change...to bad. If it's not a show-stopper there, why should it be here?

so you could for example say you need at least one

Disjunctive ("or", not "and") dependencies are completely unrelated to what is being discussed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we try to solve the problem and deal with various back compact issues at the same (not library, but Cargo itself back compat), I think we'll just melt our brains.

First why should agree on an ideal design*, second we should try to figure out a migration plan to get there, third we should adjust the destination of it's not possible.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I don't think this is special case to that. Consider if default and default-features = and all that didn't exist. This would still be solution.

Unless I am missing some subtle distinction, having empty-features = false with this RFC is effectively equivalent to RFC 3283, where every feature in the crate is included in the feature-bases. Sure, the syntax is a little different because in 3283 you would need to put one of the features in the base attribute rather than features attribute, but that is a very surface-level detail. In both cases, you have to specify at least one feature. However, RFC 3283 is strictly more flexible, because rather than always requiring you to require one of any feature in the crate. You can limit the requirement to a subset of the features. I don't see any argument in this RFC on why having a boolean to require "at least one feature" is a superior option to having a set of features, and requiring at least feature from that set (or possibly multiple such sets).

Remember Rust itself has the same name issue! If you end up making a new version function which deserves the name more than the old version and don't want to make a breaking change...to [sic] bad.

It's not quite the same. It isn't just that you can't use the name of an existing feature for a new feature. It is that if you add a new feature that was previously part of the "base", then it can potentially double the number of features that you need. If you do this multiple times, it can create quite mess, and you'll end with things like foo-without-bar-without-baz-without-soup.

This means creating new `websocket-without-http2`, `tls-without-http2`, `compression-without-http2`, `compression-brotli-without-http2`, `compression-gzip-without-http2` features in order for other crates to depend on them without pulling in http2 support.

Note that this is only a problem for new features that existing features or orthogonal too.
In many cases, existing features will naturally (not just for back compat) depend on the new features, and then there is no need or possibility to introduce `...-without-...` siblings to those features.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But in many cases existing features won't naturally depend on the new features. I don't know for sure which would actually be more prevalent, but my intuition is that even if that is true for some features, it is probably pretty rare that all existing features will depend on the new feature, so you will end up with at least some -without- siblings, whose existence is necessary only for backwards compatibility with packages that only included that one feature.

@ehuss ehuss added the T-cargo Relevant to the Cargo team, which will review and decide on the RFC. label Nov 15, 2022
Comment on lines +183 to +186
## Empty feature set is empty library.

An alternative is not to ban the empty feature set, but ensure it always translates to the empty library.
I.e. to require that *all* items must be dependent upon *some* feature; everything needs a `cfg`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something a crate could already do, right? So in principle we don't need a new cargo feature to make this possible. The problem is that doing this to an existing crate requires one semver bump to make the no-feature-lib empty.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, right. I suppose making the cargo init crate have a default feature and #![cfg(feature = "default")] might do the trick.

crate with an empty feature set is disallowed and invalidates the solution.
The `default` feature counts as a member of that set when `default-features = true`.

The solver shall avoid such solutions (so as not break old versions of libraries without `at-least-one-feature` being "discoverable").
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How? Is it supposed to just pick a feature and enable that?

I am also confused by the paragraph on why adding empty-features = false is not a breaking change, which is probably related to my confusion about this sentence.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just meant if no feature is enable than the plan is invalid, and it must throw it out. (If all plans don't enable any feature for a empty-features = false crate, then no plans are valid)

Is it supposed to just pick a feature and enable that?

Hehe I didn't even think of that. I suppose it is quite easy to take any such invalid plan and make it valid in this way, but yeah, ew.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I get it, so the reason this is semver compatible to add is that cargo will refuse to use the newer version because that would violate this condition -- so it is stuck with the old version?

That makes sense, but could be explained in a bit more detail to make it more clear.

@joshtriplett
Copy link
Member

I think there are a few separate problems this is attempting to solve:

  • Improving the handling of default-features to the point that it's no longer a semver hazard.
  • Having "select exactly one" features.
  • Having "select at least one" features.

In my opinion, I think these would best be solved by different approaches:

  • To improve the handling of default-features, we should have "negative features", such that dependent crates specify "default except for features X and Y", and adding a new default-enabled feature is not a breaking change.
  • To improve the handling of "select exactly one" features, we should have enum-valued features, and the "global features" mechanism that @epage and others have been proposing.
  • To improve the handling of "select at least one" features, I think we should use a combination of enum-valued features and boolean features. For instance, suppose you have options abc, def, and ghi, and you want people to have to enable at least one of those. You could have an enum-valued feature default-thing abc, def, and ghi, and then default-thing::abc could depend on the abc boolean feature, and so on. That way, you have to pick at least one, and you can optionally choose to enable others. (This is also convenient if your library crate wants to have a default amongst the enabled options.)

I think the combination of those would solve this family of problems.

Is there a use case that this RFC solves that those would not? Or, an advantage to doing this in addition to those?

@Nemo157
Copy link
Member

Nemo157 commented May 13, 2024

  • To improve the handling of default-features, we should have "negative features", such that dependent crates specify "default except for features X and Y", and adding a new default-enabled feature is not a breaking change.

IMO this defeats the purpose of default-features = false, the point is that I don't want to waste time compiling features I don't use, but if I can only disable features once I know about them I need to continuously keep adding new negative features to my list (and I must continuously do this and release new versions for all library crates because otherwise dependents cannot disable those features).

There are still problems with breaking changes too, if you have a no_std supporting library then adding a new default-enabled std-using feature is a breaking change to dependents that are building it in the no_std configuration. Similarly if there are other platform-specific features that cannot be cfg guarded otherwise.


The approach I've really desired for a while is to remove default-features in a future resolver/edition (act like it is always set to false) and instead have the default feature just used by cargo add to determine a list of features to add when adding a new dependency. This makes it explicitly obvious that changing the set does not affect existing dependents. If you want to reserve the ability to split code up into features in the future, you just add a feature covering all your code from the start and can then split that up into-sub-features as you want.

@joshtriplett
Copy link
Member

IMO this defeats the purpose of default-features = false, the point is that I don't want to waste time compiling features I don't use, but if I can only disable features once I know about them I need to continuously keep adding new negative features to my list (and I must continuously do this and release new versions for all library crates because otherwise dependents cannot disable those features).

If you don't have to know about a feature in order to disable it (or, in other words, if you can disable a feature you don't know about), then creating a new default-enabled feature is still a breaking change. The goal would be for creating new default-enabled features to stop being a breaking change.

@tbu-
Copy link
Contributor

tbu- commented May 13, 2024

If you don't have to know about a feature in order to disable it (or, in other words, if you can disable a feature you don't know about), then creating a new default-enabled feature is still a breaking change. The goal would be for creating new default-enabled features to stop being a breaking change.

The problem is that there are two cases for a new default-enabled feature.

  1. It adds functionality. In this case, the default-features = false user wants to disable it.
  2. It makes existing functionality optional. In this case, the default-features = false user wants to enable it. (And potentially disable it at some later point, if it's deemed unnecessary.)

@djc
Copy link
Contributor

djc commented May 14, 2024

The approach I've really desired for a while is to remove default-features in a future resolver/edition (act like it is always set to false) and instead have the default feature just used by cargo add to determine a list of features to add when adding a new dependency. This makes it explicitly obvious that changing the set does not affect existing dependents. If you want to reserve the ability to split code up into features in the future, you just add a feature covering all your code from the start and can then split that up into-sub-features as you want.

I wouldn't really like to have to rely on cargo add like this -- I still edit my Cargo manifests manually most of the time.

@epage
Copy link
Contributor

epage commented May 21, 2024

@rfcbot postpone

While I suspect we'll need something like this as part of our feature evolution story, I don't think this exact RFC is it and the Cargo team has not had the time to work with the author to shepherd this to completion. I think we should be more clear about that and officially postpone this. We can do iterate more on the design work before coming back to the RFC stage.

@rfcbot
Copy link
Collaborator

rfcbot commented May 21, 2024

Team member @epage has proposed to postpone this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Currently awaiting signoff of all team members in order to enter the final comment period. disposition-postpone This RFC is in PFCP or FCP with a disposition to postpone it. labels May 21, 2024
@rfcbot rfcbot added final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. and removed proposed-final-comment-period Currently awaiting signoff of all team members in order to enter the final comment period. labels Jun 14, 2024
@rfcbot
Copy link
Collaborator

rfcbot commented Jun 14, 2024

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this RFC. to-announce and removed final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. labels Jun 24, 2024
@rfcbot
Copy link
Collaborator

rfcbot commented Jun 24, 2024

The final comment period, with a disposition to postpone, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

This is now postponed.

@rfcbot rfcbot added postponed RFCs that have been postponed and may be revisited at a later time. and removed disposition-postpone This RFC is in PFCP or FCP with a disposition to postpone it. labels Jun 24, 2024
@rfcbot rfcbot closed this Jun 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
finished-final-comment-period The final comment period is finished for this RFC. postponed RFCs that have been postponed and may be revisited at a later time. T-cargo Relevant to the Cargo team, which will review and decide on the RFC. to-announce
Projects
Archived in project
Status: Unreviewed
Development

Successfully merging this pull request may close these issues.