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

RFC: #[cfg(accessible(..) / version(..))] #2523

Open
wants to merge 43 commits into
base: master
from

Conversation

Projects
None yet
@Centril
Contributor

Centril commented Aug 12, 2018

🖼️ Rendered

📝 Summary

Permit users to #[cfg(..)] on whether:

  • they have a certain minimum Rust version (#[cfg(version(1.27))]).
  • a certain external path is accessible (#[cfg(accessible(::std::mem::ManuallyDrop))]).

💖 Thanks

To @eddyb, @rpjohnst, @kennytm, @aturon, and @rkruppe for discussing the feature with me.
To @Mark-Simulacrum, @MajorBreakfast, @alexreg, @alercah, and @joshtriplett for reviewing the draft version of this RFC.

Centril added some commits Aug 10, 2018

@Centril Centril added the T-lang label Aug 12, 2018

@Centril Centril self-assigned this Aug 12, 2018

@Centril Centril changed the title from RFC: #[cfg(accessible(..) / version(..) / nightly)] to RFC: #[cfg(accessible(..) / version = ".." / nightly)] Aug 12, 2018

@Centril

This comment has been minimized.

Show comment
Hide comment
@Centril

Centril Aug 12, 2018

Contributor

cc @MajorBreakfast re. use case for futures. :)

Contributor

Centril commented Aug 12, 2018

cc @MajorBreakfast re. use case for futures. :)

@joshtriplett

This comment was marked as outdated.

Show comment
Hide comment
@joshtriplett

joshtriplett Aug 12, 2018

Member

I like most of this, but I'm hesitant to support "nightly" rather than some specific feature flag or path.

Member

joshtriplett commented Aug 12, 2018

I like most of this, but I'm hesitant to support "nightly" rather than some specific feature flag or path.

@killercup

This comment has been minimized.

Show comment
Hide comment
@killercup

killercup Aug 12, 2018

Member

I agree with @joshtriplett and would even say that version checks are dangerous.

I would say that feature detection like #[cfg(feature_available(foo_bar)] is a great alternative to both #[cfg(nightly)] and #[cfg(version = "1.27")] for detecting language features.

It will require us to use feature flags in more disciplined way however – we can't remove them or drastically change their implementations (without using a new feature name) if we want people to automatically get them once they become stable/once they upgrade their compiler. For alternative compiler implementations we would also need to document these features in a more specification-like manner. (So, for example, I can write #[cfg(feature_available(conservative_impl_trait)] and mrustc will skip that item until it gains that feature.)


Some other notes, that may also fit the Prior Art section:

On the web platform, it took a while to learn that checking vendors and versions ("Chrome 14" in this case instead of "nightly" and "> 1.27") was not the right approach. Today, searching for "web feature detection" gives me a document from Microsoft with this as the first headline:

The Case Against Browser Detection

MDN (web platform docs, maintained by Mozilla), has this page on the topic, that contains this note:

Before we move on, we'd like to say one thing up front — don't confuse feature detection with browser sniffing (detecting what specific browser is accessing the site) — this is a terrible practice that should be discouraged at all costs. […]

Those are pretty strong words.

Member

killercup commented Aug 12, 2018

I agree with @joshtriplett and would even say that version checks are dangerous.

I would say that feature detection like #[cfg(feature_available(foo_bar)] is a great alternative to both #[cfg(nightly)] and #[cfg(version = "1.27")] for detecting language features.

It will require us to use feature flags in more disciplined way however – we can't remove them or drastically change their implementations (without using a new feature name) if we want people to automatically get them once they become stable/once they upgrade their compiler. For alternative compiler implementations we would also need to document these features in a more specification-like manner. (So, for example, I can write #[cfg(feature_available(conservative_impl_trait)] and mrustc will skip that item until it gains that feature.)


Some other notes, that may also fit the Prior Art section:

On the web platform, it took a while to learn that checking vendors and versions ("Chrome 14" in this case instead of "nightly" and "> 1.27") was not the right approach. Today, searching for "web feature detection" gives me a document from Microsoft with this as the first headline:

The Case Against Browser Detection

MDN (web platform docs, maintained by Mozilla), has this page on the topic, that contains this note:

Before we move on, we'd like to say one thing up front — don't confuse feature detection with browser sniffing (detecting what specific browser is accessing the site) — this is a terrible practice that should be discouraged at all costs. […]

Those are pretty strong words.

@Ixrec

This comment has been minimized.

Show comment
Hide comment
@Ixrec

Ixrec Aug 12, 2018

Contributor

I don't think the browser versioning situation is a good analogue for the Rust compiler.

First, the browser is special because no Javascript developer controls what browser versions their code runs on. Every Rust developer knows what Rust compiler version they're on, many of them can upgrade their Rust compiler whenever they want, and most importantly, no users of compiled Rust programs need any version of the Rust toolchain to run them.

Second, one of the biggest problems with browser detection was scripts trying to detect vendor (IE vs Firefox vs Opera) rather than version (IE5 vs IE6). The former is harmful to the ecosystem because it leads to scripts saying "only use shiny new feature on Firefox" even after IE implements the shiny feature or Opera gets invented and ships the shiny feature on day one. That forced IE/Opera/etc to either always appear inferior or just spoof Firefox. However, detecting IE5 vs IE6 does not have that problem. If IE v6 exists at all, then IE v5 probably isn't getting any new features, so no naive code will accidentally refuse to give it code it can handle. The reason that doesn't work in the browser world is that there is no versioning scheme which all browsers are expected to uniformly support, so it's not possible to implement version detection without vendor detection (also, feature detection was a viable alternative for the most critical use cases). However, with Rust, like the RFC said, it is assumed that alternative compilers will have to match rustc's versioning scheme, and after Rust 1.27 comes out you don't expect Rust 1.26 to get any new features, so you can do version detection without vendor detection. And of course, this RFC does not propose any vendor detection like #[cfg(compiler = "rustc")] and #[cfg(compiler = "mrustc")].

So I don't see any serious danger in supporting nightly and version.

I do think feature detection on its own is insufficient, simply because no "feature" has a stable API until... it gets stabilized. So unless we're going to say that no crates in the ecosystem should ever attempt conditional support for nightly features (we aren't, right?), then nightly seems like a net win to me.

I believe the same argument extends to version. It's tempting to say that we could make "if feature NLL is enabled" return true on any language version after NLL gets stabilized, but that doesn't work in general because stable NLL's behavior may differ from nightly NLL. In fact, it's very common to only stabilize a subset of the nightly feature. We could make it work by requiring a new feature flag be defined for any language feature that's getting stabilized, but I'm not sure #[cfg(feature = "stable-NLL-part-1")] is really any better than #[cfg(version = "1.30")] or whatever since either way the programmer has to consciously add a magic value to their code after stabilization, and "stable-NLL-part-1" is essentially an alias for "1.30".

That argument doesn't apply to the browser world because browsers have always allowed us to use "experimental" features on stable versions, which turned them into de facto stable features. As long as Rust sticks to the whole "stable means stable" thing, I don't think we have to worry about that.

Contributor

Ixrec commented Aug 12, 2018

I don't think the browser versioning situation is a good analogue for the Rust compiler.

First, the browser is special because no Javascript developer controls what browser versions their code runs on. Every Rust developer knows what Rust compiler version they're on, many of them can upgrade their Rust compiler whenever they want, and most importantly, no users of compiled Rust programs need any version of the Rust toolchain to run them.

Second, one of the biggest problems with browser detection was scripts trying to detect vendor (IE vs Firefox vs Opera) rather than version (IE5 vs IE6). The former is harmful to the ecosystem because it leads to scripts saying "only use shiny new feature on Firefox" even after IE implements the shiny feature or Opera gets invented and ships the shiny feature on day one. That forced IE/Opera/etc to either always appear inferior or just spoof Firefox. However, detecting IE5 vs IE6 does not have that problem. If IE v6 exists at all, then IE v5 probably isn't getting any new features, so no naive code will accidentally refuse to give it code it can handle. The reason that doesn't work in the browser world is that there is no versioning scheme which all browsers are expected to uniformly support, so it's not possible to implement version detection without vendor detection (also, feature detection was a viable alternative for the most critical use cases). However, with Rust, like the RFC said, it is assumed that alternative compilers will have to match rustc's versioning scheme, and after Rust 1.27 comes out you don't expect Rust 1.26 to get any new features, so you can do version detection without vendor detection. And of course, this RFC does not propose any vendor detection like #[cfg(compiler = "rustc")] and #[cfg(compiler = "mrustc")].

So I don't see any serious danger in supporting nightly and version.

I do think feature detection on its own is insufficient, simply because no "feature" has a stable API until... it gets stabilized. So unless we're going to say that no crates in the ecosystem should ever attempt conditional support for nightly features (we aren't, right?), then nightly seems like a net win to me.

I believe the same argument extends to version. It's tempting to say that we could make "if feature NLL is enabled" return true on any language version after NLL gets stabilized, but that doesn't work in general because stable NLL's behavior may differ from nightly NLL. In fact, it's very common to only stabilize a subset of the nightly feature. We could make it work by requiring a new feature flag be defined for any language feature that's getting stabilized, but I'm not sure #[cfg(feature = "stable-NLL-part-1")] is really any better than #[cfg(version = "1.30")] or whatever since either way the programmer has to consciously add a magic value to their code after stabilization, and "stable-NLL-part-1" is essentially an alias for "1.30".

That argument doesn't apply to the browser world because browsers have always allowed us to use "experimental" features on stable versions, which turned them into de facto stable features. As long as Rust sticks to the whole "stable means stable" thing, I don't think we have to worry about that.

@kevinmehall

This comment was marked as outdated.

Show comment
Hide comment
@kevinmehall

kevinmehall Aug 12, 2018

One potential drawback of accessible combined with cfg_attr(nightly, feature(...)) is that it can break code that worked on a previous stable release when the feature is later stabilized in modified form.

As an example, let's say a popular library contains

#![cfg_attr(nightly, feature(some_feature))]
#[cfg(accessible(::std::foo:SomeFeature))]
use std::foo:SomeFeature;

#[cfg(not(accessible(::std::foo:SomeFeature)))]
struct SomeFeature { ... }

and compiles with stable rustc 1.35 by defining its own substitute for SomeFeature. Meanwhile, SomeFeature comes up for stabilization, and as often happens, a few of its methods get final names and tweaked type signatures prior to stabilization in 1.38. On stable 1.38 this struct is now accessible, but this causes the library to fail to compile because it's using method names and/or argument types that are no longer correct. Perhaps it's ample warning that it would also fail to compile on nightly for a while beforehand, but it does break the guarantee that if it compiles on stable 1.37, it must compile on 1.38.

cfg(version = "1.38") technically also has this possibility, but seems less likely to happen in practice, as one is unlikely to write it without knowing what's been stabilized in that version, and hopefully testing on that version.

kevinmehall commented Aug 12, 2018

One potential drawback of accessible combined with cfg_attr(nightly, feature(...)) is that it can break code that worked on a previous stable release when the feature is later stabilized in modified form.

As an example, let's say a popular library contains

#![cfg_attr(nightly, feature(some_feature))]
#[cfg(accessible(::std::foo:SomeFeature))]
use std::foo:SomeFeature;

#[cfg(not(accessible(::std::foo:SomeFeature)))]
struct SomeFeature { ... }

and compiles with stable rustc 1.35 by defining its own substitute for SomeFeature. Meanwhile, SomeFeature comes up for stabilization, and as often happens, a few of its methods get final names and tweaked type signatures prior to stabilization in 1.38. On stable 1.38 this struct is now accessible, but this causes the library to fail to compile because it's using method names and/or argument types that are no longer correct. Perhaps it's ample warning that it would also fail to compile on nightly for a while beforehand, but it does break the guarantee that if it compiles on stable 1.37, it must compile on 1.38.

cfg(version = "1.38") technically also has this possibility, but seems less likely to happen in practice, as one is unlikely to write it without knowing what's been stabilized in that version, and hopefully testing on that version.

@Centril

This comment was marked as outdated.

Show comment
Hide comment
@Centril

Centril Aug 12, 2018

Contributor

@kevinmehall

As an example, let's say a popular library contains

This is true; and I'll include it (in a bit...) in the RFC as a drawback.

However, this is mainly a problem with using accessible(std::foo:SomeFeature) and its negation not(accessible(std::foo:SomeFeature)) to migrate things from one crate to another (as with .flatten()). If a user writes this, they need to be reasonably certain that nightly changes are unlikely to happen.

On stable 1.38 this struct is now accessible, but this causes the library to fail to compile because it's using method names and/or argument types that are no longer correct.

What the library author can do if they worry about method names is to use accessible on those (in conjunction with using all..). However, they will not be able to deal with type signatures. Hopefully, it will be fairly rare that the same method name changes the type signature.

Perhaps it's ample warning that it would also fail to compile on nightly for a while beforehand, but it does break the guarantee that if it compiles on stable 1.37, it must compile on 1.38.

I believe so. If you has CI builds that target nightly (and you should if you is doing things like this..) then your nightly builds will fail and you will notice. You can then issue a patch release which either removes the nightly feature, or adjusts the usage of it.

cfg(version = "1.38") technically also has this possibility, but seems less likely to happen in practice, as one is unlikely to write it without knowing what's been stabilized in that version, and hopefully testing on that version.

You can do the same thing with accessible(..) for features that you know have stabilized. The risk, which exists, starts with nightly rather than accessible(..) I would say. It seems to me that users should mostly use nightly + accessible for features that have been stabilized in nightly but which have not reached stable yet. Features that are in (P)FCP to be stabilized are probably also less risky.

Contributor

Centril commented Aug 12, 2018

@kevinmehall

As an example, let's say a popular library contains

This is true; and I'll include it (in a bit...) in the RFC as a drawback.

However, this is mainly a problem with using accessible(std::foo:SomeFeature) and its negation not(accessible(std::foo:SomeFeature)) to migrate things from one crate to another (as with .flatten()). If a user writes this, they need to be reasonably certain that nightly changes are unlikely to happen.

On stable 1.38 this struct is now accessible, but this causes the library to fail to compile because it's using method names and/or argument types that are no longer correct.

What the library author can do if they worry about method names is to use accessible on those (in conjunction with using all..). However, they will not be able to deal with type signatures. Hopefully, it will be fairly rare that the same method name changes the type signature.

Perhaps it's ample warning that it would also fail to compile on nightly for a while beforehand, but it does break the guarantee that if it compiles on stable 1.37, it must compile on 1.38.

I believe so. If you has CI builds that target nightly (and you should if you is doing things like this..) then your nightly builds will fail and you will notice. You can then issue a patch release which either removes the nightly feature, or adjusts the usage of it.

cfg(version = "1.38") technically also has this possibility, but seems less likely to happen in practice, as one is unlikely to write it without knowing what's been stabilized in that version, and hopefully testing on that version.

You can do the same thing with accessible(..) for features that you know have stabilized. The risk, which exists, starts with nightly rather than accessible(..) I would say. It seems to me that users should mostly use nightly + accessible for features that have been stabilized in nightly but which have not reached stable yet. Features that are in (P)FCP to be stabilized are probably also less risky.

@mark-i-m

This comment was marked as outdated.

Show comment
Hide comment
@mark-i-m

mark-i-m Aug 12, 2018

Contributor

I had a half-baked idea as I was reading: allow lib authors to write #[cfg(nightly)] to create a nightly version of their crate. If somebody is using a nightly compiler, then code marked nightly is enabled. The nightly version of a crate is considered unstable and may require the latest compiler version to work.

In this way, crates can have a stable and nightly version, just like the compiler toolchain. If you're using nightly rust you get nightly versions of crates too.

Contributor

mark-i-m commented Aug 12, 2018

I had a half-baked idea as I was reading: allow lib authors to write #[cfg(nightly)] to create a nightly version of their crate. If somebody is using a nightly compiler, then code marked nightly is enabled. The nightly version of a crate is considered unstable and may require the latest compiler version to work.

In this way, crates can have a stable and nightly version, just like the compiler toolchain. If you're using nightly rust you get nightly versions of crates too.

@mark-i-m

This comment has been minimized.

Show comment
Hide comment
@mark-i-m

mark-i-m Aug 15, 2018

Contributor

A good idea; however, I think it is out of this RFC's scope.

Fair enough. I think it could be plausibly related in that I think this problem gets worse if we make features easy to use but they remain hard to find. But I don't want to over complicate this RFC either.

Contributor

mark-i-m commented Aug 15, 2018

A good idea; however, I think it is out of this RFC's scope.

Fair enough. I think it could be plausibly related in that I think this problem gets worse if we make features easy to use but they remain hard to find. But I don't want to over complicate this RFC either.

@clarcharr

This comment has been minimized.

Show comment
Hide comment
@clarcharr

clarcharr Aug 15, 2018

Contributor

I feel that if #[cfg(version = ...)] exists, it should support the full semver spec, not just a static version string. If people want to do weird constraints, they shouldn't be allowed to for this case but use version_check otherwise-- that way, if we really decide a certain way of checking versions is a bad practice, we can lint it more easily.

Contributor

clarcharr commented Aug 15, 2018

I feel that if #[cfg(version = ...)] exists, it should support the full semver spec, not just a static version string. If people want to do weird constraints, they shouldn't be allowed to for this case but use version_check otherwise-- that way, if we really decide a certain way of checking versions is a bad practice, we can lint it more easily.

@Nemo157

This comment has been minimized.

Show comment
Hide comment
@Nemo157

Nemo157 Aug 16, 2018

Contributor

I agree with others that introducing #[cfg(nightly)] will likely cause more issues than it resolves. We recently had breakage with futures nightly flag because of changes to an existing unstable feature. Because this was hidden behind an explicit flag in futures it wouldn't have affected users that weren't using this functionality but were still building on nightly for some other reason. I would even say that having just a single nightly flag in futures is a bit too broad and we should go closer to the std model of having individual flags for individually usable unstable features.

The idea of having #[cfg(version = ...)] using semver is interesting (@clarcharr I assume #[cfg(feature = ...)] was a typo?), I have hit bugs in old releases in the past and being able to add workarounds that only apply for these specific releases could be useful in cases where the workaround has a performance impact.

Contributor

Nemo157 commented Aug 16, 2018

I agree with others that introducing #[cfg(nightly)] will likely cause more issues than it resolves. We recently had breakage with futures nightly flag because of changes to an existing unstable feature. Because this was hidden behind an explicit flag in futures it wouldn't have affected users that weren't using this functionality but were still building on nightly for some other reason. I would even say that having just a single nightly flag in futures is a bit too broad and we should go closer to the std model of having individual flags for individually usable unstable features.

The idea of having #[cfg(version = ...)] using semver is interesting (@clarcharr I assume #[cfg(feature = ...)] was a typo?), I have hit bugs in old releases in the past and being able to add workarounds that only apply for these specific releases could be useful in cases where the workaround has a performance impact.

@clarcharr

This comment has been minimized.

Show comment
Hide comment
@clarcharr

clarcharr Aug 16, 2018

Contributor

It was a typo; it's been fixed. And yeah, I agree that being able to add workarounds for specific versions is helpful.

Contributor

clarcharr commented Aug 16, 2018

It was a typo; it's been fixed. And yeah, I agree that being able to add workarounds for specific versions is helpful.

@SimonSapin

This comment has been minimized.

Show comment
Hide comment
@SimonSapin

SimonSapin Aug 17, 2018

Contributor

I would like the documentation of the feature to have something to this effect. I have the feeling that it will be abused for this purpose, because not everybody thinks so hard about the implications of stability.

To be clear, I was making an argument against adding cfg(nightly) at all.

This depends on when you decide 1.28 starts.

So rustc 1.28.0-nightly (b68432d56 2018-06-12) would not match cfg(version = "1.28")? That would be… interesting to document and teach.

Contributor

SimonSapin commented Aug 17, 2018

I would like the documentation of the feature to have something to this effect. I have the feeling that it will be abused for this purpose, because not everybody thinks so hard about the implications of stability.

To be clear, I was making an argument against adding cfg(nightly) at all.

This depends on when you decide 1.28 starts.

So rustc 1.28.0-nightly (b68432d56 2018-06-12) would not match cfg(version = "1.28")? That would be… interesting to document and teach.

@eddyb

This comment has been minimized.

Show comment
Hide comment
@eddyb

eddyb Aug 18, 2018

Member

Note that if you want custom syntax, you can pick, e.g. #[cfg(version(=1.29.1)] for semver specs.
As long as you pick name(...), everything inside the parens has similar flexibility to a macro.
(that's not to say the syntax is accepted right now, but that we can easily allow it)

Member

eddyb commented Aug 18, 2018

Note that if you want custom syntax, you can pick, e.g. #[cfg(version(=1.29.1)] for semver specs.
As long as you pick name(...), everything inside the parens has similar flexibility to a macro.
(that's not to say the syntax is accepted right now, but that we can easily allow it)

@Centril

This comment has been minimized.

Show comment
Hide comment
@Centril

Centril Aug 19, 2018

Contributor

Updates:

  • The syntax of #[cfg(version = "<semver>")] has been changed to #[cfg(version(<semver>))] per rationale and suggestion given by @eddyb.

  • The #[cfg(nightly)] feature has been dropped from the proposal.

Contributor

Centril commented Aug 19, 2018

Updates:

  • The syntax of #[cfg(version = "<semver>")] has been changed to #[cfg(version(<semver>))] per rationale and suggestion given by @eddyb.

  • The #[cfg(nightly)] feature has been dropped from the proposal.

@Centril

This comment has been minimized.

Show comment
Hide comment
@Centril

Centril Aug 19, 2018

Contributor

Updates:

  • I've added an in-depth discussion (in the section on Unresolved questions) on the possible exact semantics of version(..) wrt. mid-cycle nightly versions.
    cc @Mark-Simulacrum on this.
Contributor

Centril commented Aug 19, 2018

Updates:

  • I've added an in-depth discussion (in the section on Unresolved questions) on the possible exact semantics of version(..) wrt. mid-cycle nightly versions.
    cc @Mark-Simulacrum on this.

@Centril Centril changed the title from RFC: #[cfg(accessible(..) / version = ".." / nightly)] to RFC: #[cfg(accessible(..) / version(..))] Aug 19, 2018

@joshtriplett

This comment has been minimized.

Show comment
Hide comment
@joshtriplett

joshtriplett Aug 31, 2018

Member

I'd very much like to see the followup RFC for has_attr (and other related items like has_lint) as soon as possible, to avoid having cfg(version(...)) propagate through the ecosystem for that use case. But I do feel that what's proposed in this RFC is ready.

@rfcbot fcp merge

Member

joshtriplett commented Aug 31, 2018

I'd very much like to see the followup RFC for has_attr (and other related items like has_lint) as soon as possible, to avoid having cfg(version(...)) propagate through the ecosystem for that use case. But I do feel that what's proposed in this RFC is ready.

@rfcbot fcp merge

@rfcbot

This comment has been minimized.

Show comment
Hide comment
@rfcbot

rfcbot Aug 31, 2018

Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged teams:

No concerns currently listed.

Once a majority of reviewers approve (and none object), 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 commented Aug 31, 2018

Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged teams:

No concerns currently listed.

Once a majority of reviewers approve (and none object), 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.

@repax

This comment has been minimized.

Show comment
Hide comment
@repax

repax Sep 2, 2018

I think that #[cfg(version(...))] has some problems. First, it's only an indirect indication of the available language features. What a version captures is the set of features that happen to be available at a particular point in time, most of which are not crucial for what the function needs.

Secondly, some features change over time or are deprecated or removed. The set of available features is not monotonically increasing with the rustc version, so the appropriate version of rustc for a specific set of features is not so obvious.

With more than one Rust compiler implementation this version number is less interesting or meaningful. One cannot require all implementations to follow exactly the same developmental path. Just take a look at the diversity of implemented features for these C++ compilers, courtesy of cppreference.com.

#[edition = ...] could be a good alternative for a coarsely grained description of required language features.

repax commented Sep 2, 2018

I think that #[cfg(version(...))] has some problems. First, it's only an indirect indication of the available language features. What a version captures is the set of features that happen to be available at a particular point in time, most of which are not crucial for what the function needs.

Secondly, some features change over time or are deprecated or removed. The set of available features is not monotonically increasing with the rustc version, so the appropriate version of rustc for a specific set of features is not so obvious.

With more than one Rust compiler implementation this version number is less interesting or meaningful. One cannot require all implementations to follow exactly the same developmental path. Just take a look at the diversity of implemented features for these C++ compilers, courtesy of cppreference.com.

#[edition = ...] could be a good alternative for a coarsely grained description of required language features.

@Nemo157

This comment has been minimized.

Show comment
Hide comment
@Nemo157

Nemo157 Sep 2, 2018

Contributor

Secondly, some features change over time or are deprecated or removed. The set of available features is not monotonically increasing with the rustc version, so the appropriate version of rustc for a specific set of features is not so obvious.

According to Rust’s stability guarantee the feature set is monotonically increasing (within an edition, assuming nightly features are excluded).

Contributor

Nemo157 commented Sep 2, 2018

Secondly, some features change over time or are deprecated or removed. The set of available features is not monotonically increasing with the rustc version, so the appropriate version of rustc for a specific set of features is not so obvious.

According to Rust’s stability guarantee the feature set is monotonically increasing (within an edition, assuming nightly features are excluded).

@repax

This comment has been minimized.

Show comment
Hide comment
@repax

repax Sep 2, 2018

"Within" yes, which is why cfg(version(...) is problematic across the longer history / evolution of the language. Features can be removed in a later edition.

repax commented Sep 2, 2018

"Within" yes, which is why cfg(version(...) is problematic across the longer history / evolution of the language. Features can be removed in a later edition.

@kennytm

This comment has been minimized.

Show comment
Hide comment
@kennytm

kennytm Sep 2, 2018

Member

@repax every crate can choose which edition to compile with and shouldn't interfere with other crates, and thus #[cfg(edition)] makes no sense.

Member

kennytm commented Sep 2, 2018

@repax every crate can choose which edition to compile with and shouldn't interfere with other crates, and thus #[cfg(edition)] makes no sense.

@repax

This comment has been minimized.

Show comment
Hide comment
@repax

repax Sep 3, 2018

@kennytm, so maybe we should make it #[edition = ...] instead of #[cfg(edition = ...)]. Would that be sufficient?

repax commented Sep 3, 2018

@kennytm, so maybe we should make it #[edition = ...] instead of #[cfg(edition = ...)]. Would that be sufficient?

@Nemo157

This comment has been minimized.

Show comment
Hide comment
@Nemo157

Nemo157 Sep 3, 2018

Contributor

@repax edition is set in each crates Cargo.toml, there is no need for the ability to detect it in the source code. Features are mostly independent of editions, the majority of new features will be available in all editions. It is only features that require breaking changes that will not be supported in old editions. For an example async fn are currently available (behind a nightly feature flag) in both edition 2015 and 2018, async {} blocks are only available in edition 2018 because async is not a keyword in edition 2015.

Contributor

Nemo157 commented Sep 3, 2018

@repax edition is set in each crates Cargo.toml, there is no need for the ability to detect it in the source code. Features are mostly independent of editions, the majority of new features will be available in all editions. It is only features that require breaking changes that will not be supported in old editions. For an example async fn are currently available (behind a nightly feature flag) in both edition 2015 and 2018, async {} blocks are only available in edition 2018 because async is not a keyword in edition 2015.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment