TL;DR Experimental features are features that land in tree before going through the RFC process with the purpose of having end users evaluate them and producing a better RFC document. These experimental features will be maintained as feature branches, to not block the development of the master branch, for a predetermined amount of time.
Overview
Introduce the concept of "experimental features" into the RFC process. These features go through an experimentation process, where they get implemented so end users can evalute them, before going through the existing RFC process (at that point they become unstable features).
Motivation
Sometimes is hard to come up with a convincing motivation for a RFC because it's hard to predict how a feature will be used in practice or whether the use cases one comes up with will have positive / significant impact in the ecosystem.
Other times, it's hard to evaluate the correctness of a RFC design because one can't foresee all the interactions of the proposed feature with all the other existing ones.
This document proposes a mechanism for implementing features without going through the RFC process with the goal of answering the above questions through end user feedback.
Detailed design
Request for Experiment
Experimental features start with a Request For Experiment (RFE) document, a lighter version of the RFC document.
The RFE document should consist of:
-
A motivation. More like a justification for the feature going through experimentation rather than through the normal RFC process.
-
An initial design.
-
Questions to answer (during the experimentation process)
The important part at this stage is collecting relevant questions about the feature. These will probably be along the lines of:
-
How does this new feature interacts with feature X, in practice?
-
Does this new feature leads to Rustic programming patterns or, instead, leads to footguns?
-
How does this feature improves the API of existing libraries?
-
Does this feature prevent the adoption of a new compiler backend (e.g. Cretonne) or third party implementation of rustc / the Rust language?
Bikeshedding the syntax at this stage is discouraged (modulo discussion about possible ambiguous grammar) as that should be left up to the RFC process.
Eligibility
What kind of features should go through an experimentation phase first?
If a feature can be implemented and evaluated out of tree (i.e. without changes to the compiler), then it should be evaluated out of tree and go through the normal RFC process.
If writing a RFC produces several unresolved questions that don't seem like they can be answered purely through discussion, then the proposed feature is a good candidate for experimentation.
Experimentation phase
Upon accepting the RFC, the Rust team will decide on a experimentation period for the feature. This period could be measured in Rust cycles. For example: "the experiment will run for three 6-week cycles".
Then an implementation will be sent as a PR to the rust-lang/rust repo. However, instead of merging the PR into the master branch (once it passes the test suite), it will become a feature branch. This way, the experimental feature won't block the development of the master branch.
The Rust infrastructure will produce binary artifacts once the PR is merged. Users will then be able to use rustup to try out the feature branch:
$ rustup default dev-$feature
$ rustc -V
rustc 1.17.0-dev (..)
An issue will be open in the rust-lang/rfcs repo to discuss the experimental feature. The discussion in this issue should try to answer the questions set in the RFE. This issue should also keep track of user experiences, both good and bad, with the feature.
The feature branch will receive bug fixes and be rebased on top of master when relevant during the duration of the experimentation phase. Every update to the feature branch will produce a new binary release.
Previous releases of the feature branch will be available via rustup:
$ rustup default dev-$feature-$sha
End of the experiment
Once the experiment is over, two things can happen:
If the feature didn't recieve the interest of the community, the associated feature branch will be deleted and the associated rust-lang/rfcs issue will be closed.
Otherwise, the associated rust-lang/rfcs issue will be closed and a proper RFC, that collects the insights from the experimentation phase, will be proposed. The feature branch will become frozen while the RFC is being discussed. If the RFC is accepted, the feature branch will be updated to match the RFC text, then merged into master and go through the existing stabilization process. If the RFC is closed, then the feature branch will be deleted.
Alternatives
Instead of maintaining a feature branch, we could merge the experimental feature into master and maintain it just like the other features. In that case, we may want to have more clear separation between experimental features and unstable features. Maybe #[feature(experimental($feature_name))]
.
Unresolved questions
-
Should we try to prevent users from publishing crates that use experimental features?
-
Should we keep the branches of failed experiments instead of deleting them?
-
Should we not impose a deadline for the experimentation phase?
-
What other aspects should considered for evaluating the eligibility of a feature for experimentation?
Potential candidates for experimentation:
-Z linker-flavor
That PR allows experimentation with LLD as a external linker.
What wants to be evaluated here is the benefits of embedding LLD into rustc to use it as the default linker.
LLD being a fast multiarch linker are clear benefits but having to explicitly specify startup objects, library search paths and the dynamic linker to link "Hello, world" is a clear downside.
Experimentation could let us find a solution for the downside and benchmark LLD vs GNU's ld (is the speedup worthwhile?).
Custom Dynamically Sized Types
Letting users define custom DST seems like it could lead to more ergonomic linear algebra libraries while also reducing the size of their code bases (by removing duplicate logic through Deref).
Experimentation would let us answer that question with data points like
"With custom DSTs, I reduced the size of my code base by 70%", or
"My examples now have a nicer syntax that's closer to what linear algebra users are used to. See the diff and the Python / MATLAB equivalent".
The experimental implementation doesn't need to bother with questions like "what's the best way to expose this feature (synatx, traits, etc.)", which has been one of the main topics of the RFC discussion, as long as it exposes the functionality.
the #[used]
attribute.
Prevents LLVM from optimizing away a non-exported static
that has no references to it, within a compilation unit (object file).
Seems like it would be useful in the bare metal context where a fine control over symbols and the linker is desired.
However, paired with #[link_section]
, #[used]
can be used to achieve "life before main" (using the .init_array
ELF standard) which seems like a bad idea in std
programs because "before main" also runs before the Rust runtime is initialized. But "life before main" may not be such a bad idea in bare metal contexts where there's no Rust (std
) runtime.
Again, experimentation can help answer these questions.