Survey of "High Impact" Features

Hey folks!

I'm on a bit of a mission to find a way to make it easier to gather stabilization evidence for "high impact" unstable features. By "high impact" here I don't mean "enables lots of cool stuff", but rather "meaningfully improves the quality of life of many developers". What I'm after may be easier to explain by way of a concrete example (feel free to skip it by jumping to the next horizontal line).


I currently maintain the Rust integration for AWS' internal build system. It is used by more or less all Rust projects throughout the organization, and thus any given change to it has an outsized impact, whether positive or negative. In cases where the integration between the internal build system and cargo isn't frictionless, that pain is generally felt by every engineer using Rust, which can add up to a lot of frustration. Recently, I landed a cargo feature, -Zpatch-in-config, that would address a long-standing pain-point in the Cargo integration. I have tested it myself, and it significantly improves the experience for certain common use-cases. And if it were to be deployed internally, it would solve a bunch of issues internal developers are experiencing.

Unfortunately, since it's an unstable nightly feature, I don't have a good way to test it throughout the organization. Switching to nightly isn't really an option, since at this kind of scale issues introduced to nightly will almost certainly break something, so the broad stability of stable is important. I could use the RUSTC_BOOTSTRAP=1 hack to break Rust's stability guarantees combined with -Zallow-features, but that just feels icky.


The fact that I don't have a good way to test this feature widely internally in turn means that I can't easily provide good stabilization evidence back upstream. And since this change is only likely to be useful for those integrating Cargo with other build systems at scale, chances are such evidence simply won't be reported. This is bad for the ecosystem. So, I'm trying to come up with a better way to go about this that might be applicable beyond my particular use-case.

This isn't the first time this problem has been pointed out, or solutions proposed. In fact, we've been around this a few times now:

Rather than try to propose a(nother) solution in this thread, I'd like to first try to solicit other examples of such "high impact" changes, defined roughly as:

  1. Big fan-out. Enabling the use of this feature in one place (e.g., a single build system or a single crate) would meaningfully and positively impact a large number of developers. "Large" is subjective of course, but I'd say at least 100+ developers.
  2. Stable implementation. The feature is unlikely to see significant changes before landing, and is either simple enough, or has gone through enough revisions that it'd be meaningful to test it on stable. This is important because if that's not the case, chances are it's best for the feature to be tested on nightly for the time being anyway.
  3. No cascade. The feature is impactful when enabled only at the "top level", be it at a crate with no dependents or in an external system. This is an important condition, as features that do not meet this requirement very quickly start violating Rust's stability guarantees.

If you can think of a feature that matches those criteria, I'd love to hear about it! That way, I'll be armed with a good list from which to try and craft a mechanism that might enable testing these kinds of features on the beta and stable channels! If you could include

that'd be amazing! I'll go first:


Feature: patch-in-config (Cargo)

Impact: Would save Rust developers at AWS (there are many of us :wave:) from wiping their build artifacts and lockfiles whenever first-party dependencies change.

14 Likes

Cargo has a feature -Zweak-dep-features, which allows a crate feature to depend on a feature of another crate, but without enabling that crate if it hasn't already been enabled. Without this, it's impossible to say things like "my xyz feature requires the xyz feature of the abc backend" while still keeping the abc backend itself optional.

This feature could use more testing; please give it a try in the latest Cargo nightly, and post experience reports to Tracking Issue for weak dependency features · Issue #8832 · rust-lang/cargo · GitHub .

4 Likes

Cargo also has an unstable feature strip, which allows stripping symbols or debuginfo from a binary when building for a specific profile (such as release): Unstable Features - The Cargo Book

This feature is quite easy to test; give it a try, and confirm that the built binary is stripped. If it works for you, please send an experience report to Tracking issue for `-Z strip=val` option · Issue #72110 · rust-lang/rust · GitHub .

7 Likes

Even though I desperately want that feature as well, I don't think it meets the first or third criteria for the kind of features I'm specifically looking for based on your description?

Oh, you're right, it doesn't. Sorry, I misunderstood. I'll delete it.

All good! It is a really exciting feature, I just want to make sure I specifically gather features that match this particular pattern here. Trying to design a general-purpose mechanism for testing "any exciting feature" is, I think, not tenable. Or rather, we already have the answer: use nightly :sweat_smile:

1 Like

This example is out of date, because it was stabilized in Rust 1.51, but I think the new Cargo feature resolver would have qualified before it became stable.

Looking at my company's past use of unstable features, cargo --out-dir is another that might fit. It makes it a lot easier to integrate Cargo with other build systems, which I expect is common for other production users besides us. We currently have workarounds that are compatible with stable Cargo, but they feel somewhat fragile. Enabling this feature would not be life-changing, but it could save a fair amount of duplicated work across many different Rust users.

5 Likes

Observation: I suspect that the third criteria, enabled only at the top level, effectively limits this to only cargo features, or features otherwise exposable by cargo. Any language or libs feature would want to be enabled throughout the dependency graph for full usage.

The only language feature I can think of that would fit the third criteria is #[global_allocator].

6 Likes

I have attempted to raise a couple of things that might fall into that category in the past. On the lang side:

On the libs side:

Additionally: stabilizing cargo bench:

And Rustfmt

1 Like

Thanks for the suggestions? I wonder if all of these quite fit the criteria though. Specifically:

pub(test)

I don't think this is a feature that already exists, and thus wouldn't fit 2). It's also not clear to me that it has a big fan-out (1).

cfg-if in std

This also doesn't exist as a feature, so no 2). And I have the same question around fan-out. Furthermore, this feels like it wouldn't match 3, as if one crate used the "cfg-if in std" feature, all its dependents would also need to use said feature.

Stabilize #[bench]

This is a good candidate I think — that is, it matches all the criteria. My biggest question on #[bench] is whether it's something that will ever get stabilized. My current feeling (which may be misjudged) is that bench may end up never landing, at least not in its current form, and instead be replaced by something like custom test frameworks. @SimonSapin summarized the state of affairs in 2019.

Rustfmt stability

It's not entirely clear to me what the feature is here? This seems more like a process question than an explicit feature that could be "tested" or "used".

I wonder if another candidate might be doc(cfg). It isn't quite no cascade (users may try to build transitive documentation on stable), but maybe that's ok? It's high fan out in the sense that documentation may be consumed by many developers. And it is, from what I can tell, a fairly stable feature. @jyn514 what do you think — would you consider that a feature that might fit as a "preview feature" on stable?

1 Like

rustdoc features are in kind of an (unfortunate) special spot w.r.t. stability: most (or at least a significant chunk of) public crate documentation is consumed through docs-rs, which makes docs using some somewhat recent nightly. It's already possible to experimentally adopt doc(cfg) for use only behind a doc flag enabled on docsrs, and multiple projects do similar things already.

2 Likes

-Zweak-dep-features

This one feels like it doesn't meet the "no cascade" requirement. It very much feels like you would want more parts of the ecosystem to opt into it for it to have an effect.

-Zstrip=val

I think this is a great candidate, though I worry about the =val part. When this is stabilized, presumably it'll become something like --strip=val? I think we'd probably want to wait to preview until that move is made (and it's guarded with unstable-options) to minimize friction, though I'm not sure.

No, doc(cfg) is well tested and we know what the bugs are; mostly it's waiting on https://github.com/rust-lang/rust/pull/79341.

While it absolutely benefits from being available to the ecosystem at large, it also has value even within a single crate workspace. Nonetheless, I do agree that it isn't quite the ideal fit, the way strip is.

1 Like

oom=panic setting

To me current #1 pain is lack of fallible allocations, and my servers self-destructing with abort(). Just stabilizng this would solve fallible allocations problems for me.

This is even slightly better than try_reserve(), because it automatically applies to all dependencies.

1 Like

Ah, that's an interesting one, and I agree it sounds like it would fit. Does that feature currently exist though — I couldn't find it from a cursory search through the docs?

1 Like

cfg_version or Cargo msrv

Staying on an older Rust version is a major pain. This may happen when users use a Linux-distro-provided Rust packages (because they don't know it makes a difference, or they just want all their software managed by their package manager, or have been taught that curl | sh is an insecure hack), or when they forget to run rustup update (it's not automatic) or when they need to use a specific version because of bureaucracy, or desire to bootstrap Rust via mrustc, etc.

There's a disagreement in the ecosystem whether crates should target latest-stable Rust only, or some old version, and whether Rust upgrade is a semver-major-breaking change.

This is made worse by the fact that Rust/Cargo can't clearly communicate to users that they have too-old Rust version. Instead users are told to add unstable command-line flags and/or switch to nightly Rust version. This is baffling to new users, makes them go in circles with compile errors, and makes Rust seem to require Nightly version for almost every crate, as if Rust was still very young and barely working.

If Cargo supported msrv, then:

  • authors of libraries could target latest-stable Rust without worrying about the fallout it causes.
  • users of outdated distro-bundled Rust versions would at least be better informed about the problem they face, or their builds would even just work by picking compatible crate versions instead.

This is a feature that requires crates in the ecosystem to adopt it. However, while gathering MSRV data for https://lib.rs I've noticed that there's only a small fraction of crates that is responsible for majority of broken builds. For example, just object and socket2 probably break majority of popular crates (object used by backtrace used by majority of error-handling crates, socket2 used by hyper, used in everything web-related)

1 Like

I agree the msrv feature is a welcome addition, but it doesn't seem like it fits the "no cascade" clause? The reason that's there specifically is that if a feature like that were to be made available on stable as a "preview", then if it were adopted in one crate, all of that crate's dependents would also have to adopt it. And if the feature then left preview, was changed, or was removed entirely, the dependents would have to change again.

But maybe msrv doesn't cascade, and is just ignored (with a warning) if the feature isn't available in the consumer's environment, I don't know?