MSRV-Specific Code

The Rust language itself already supports const generics, and thus supports implementing traits for arbitrary length arrays without macro expansion and redundance in compilation products. But the serde community seems to have been lacking widely support for arbitrary length arrays for a long time because of the MSRV strategy. For example, the crate serde_bytes does not support [u8, N] so far, and a PR that added that support was not merged for 4 months, seemingly because it directly raised the MSRV to 1.53, which is unacceptable for crate's MSRV strategy. (I have not actually seen the MSRV strategy of this crate, and the crate maintainer has not replied to the PR, so the above words are just my guess.) By searching I found a RFC (tracking issue) that might be able to solve this problem. However, the tracking issue was opened almost 3 years ago and has not been completed yet. I would like to know the progress.

This issue seems pretty relevant: MSRV policy for libc crate · Issue #72 · rust-lang/libs-team · GitHub

3 Likes

I've mostly cited arguments, but perhaps not very clearly expressed what I would like to see: by making crate selectable for features and code based on the user's chosen language version in a similar way to cfg, just as it does for different platforms. For the mentioned above serde_bytes example, would theoretically make it perfectly possible to make [u8; N] support available to users using language version above 1.51, while maintaining compatibility for users using language versions below that.

Conditional compilation based on rustc version is already possible and somewhat spread in the ecosystem. While direct support would be nice, build scripts can be used right now. serde uses this already to keep the MSRV at 1.13+. Requiring a new feature would not help keeping the MSRV low.

serde and other crates by the same author are all pretty much stalled concerning development, and many PRs are entirely ignored. For the specific case of serde_bytes there are alternatives available.

4 Likes

With the newly added rust-version field in Cargo.toml, it would be possible for Cargo to support an MSRV-dependent resolution which takes that field into account and selects the newest version with a compatible MSRV, even if it were gated behind a flag like -Z msrv-compatible-versions

2 Likes

A nightly-only flag requires using the nightly toolchain to generate your Cargo.lock. This is the case today with -Z minimal-versions as well (which I think is the better solution long-term, but I digress).

Using -Z minimal-versions locks you out of bugfixes which are MSRV compatible, forcing you to specify them explicitly in Cargo.toml instead of being able to pick them up automatically.

IMO the main use case for -Z minimal-versions is checking that your dependencies have their required versions properly declared and that your crate will still compile when the minimum versions are selected.

3 Likes

If a bugfix in your dependency represents a bugfix in you, it's absolutely reasonable for that to mean a patch release for you to bump the dependency edge to guarantee that patch. -Zminimal-versions isn't the only way you could be using the older dependency; normal lockfile usage and time could also result in you using the buggy version as well.

This of course doesn't mean that providing rust-version-aware dependency resolution by default isn't still both useful and desirable. But it does hint at that metadata/manifest-only package updates are also a useful thing to have access to (where the old compilation cache can potentially be reused).

That's why running cargo-audit on a -Z minimal-versions lock file is still important. Of course, bugfixes being present means that you may need to evaluate the minimum versions again.

Speaking as the author of cargo audit, it won't help you with bugfixes, only security issues.

This is the sort of manual maintenance work picking the latest compatible version automatically avoids which I was alluding to earlier.

It also means for transitive dependencies, you won't receive bugfixes until the downstream authors of your immediate dependencies bump versions in the lockfile.

This greatly increases the amount of friction involved in ensuring your code is up-to-date.

True. These are those that are "surprising" and not usually tracked. If I get an issue that some dependency releases a fix that I care about, then I bump the minimum.

Yes. Unfortunately, this means that the MSRV creeps up as crates have varying views of what it means for stability. -Z minimal-versions keeps that stable at least.

It's easy enough to force a bump by adding a direct dependency to the crate to your own Cargo.toml file. I typically comment it with a link to the issue(s) related to getting a dependency bumped.

With my Cargo team hat on: I'd love to see version resolution take rust-version into account (and emit an informational message saying it's doing so and thus not choosing a newer version), but that's quite non-trivial, as it will require resolver changes.

(Also, it's not clear if we want to do that by default, or if we want that to be an opt-in for use by people who want to keep running older versions.)

5 Likes

Learned about the serde_with crate because of some demands, although it didn't solve my demands in the end (most likely because I didn't understand how to use it). I hadn't noticed before that there was an alternative to serializing bytes in it. But it seems that introducing this whole crate for this one feature is a bit redundant.

A better option could be a theoretical [phantom-dependencies] table.

I stand behind what I said earlier that if your library's correctness relies on a bug fix in your dependency, you should upgrade your dependency requirement. Being "minimal-versions correct" isn't just about working under -Zminimal-versions, it's also about getting the appropriate versions to people who cargo add your library but already have older versions of your dependencies in their lockfile.

Especially if you're a "maximal-versions maximalist," you should be upgrading your dependency requirements for each release to be the most recent at the time of release. Or at the very least, to whatever the versions are in your lockfile. Those are the versions you tested against, so don't lie and say you work with earlier versions.

2 Likes

The projects I regularly work on have minimal-versions CI setup, so at least I know they work.

1 Like

imo specifying rust-version would be opting in.

One way of informing users that we are holding back dependencies is my idea to add a cargo outdated-like table to cargo update and cargo upgrade.

+1. If an MSRV-aware resolver were added, it would definitely be good to somehow warn users that an outdated version is being selected due to MSRV restrictions

1 Like

I'd go as far as saying: it'd be neat to proactively patch specific old versions that are distributed by distros to provide custom errors in the face of an attempt to use new features. I don't know if distro maintainers would be amenable to such "functionality" patches.