Why are the version numbers on crates.io so low?

It seems like there is quite a refusal of stable version numbers in rust crate authors. There are lots of crates that mission critical software depends on (libc, mio, winapi, rand, gcc) that have not yet reached an officially stable status. Why is that? Wouldn't using those libraries on thousands (if not millions) of machines and the time they've already been available satisfy a 1.0-release and stability guarantees? I understand that libraries like futures-rs that have existed publicly for half a year are not considered stable, but in practice, those other libraries are stable (and usually tested), but the version number says they are not. Why?

3 Likes

For the same reason that React was at version 0.14 while being used by tens of millions of people - 1.0.0 is a scary number! I don't really think there's a reason other than that.

All of the crates you mentioned only make breaking changes on 0.x -> 0.y bumps, so if you squint and pretend the leading 0. isn't there it should be equivalent to nonzero major versions.

2 Likes

That convention (which is not semver canon I think) might contribute to the low numbers - there's no need to release 1.0 early just to convey stability guarantees.

1 Like

I think it's an enjoyable thing. You provide 0.1, 0.1.1, 0.2, 0.3, etc releases with stability guarantees (no breakage within each tier) and yet have experimentation and rapid development.

To a degree the issues of:

  1. I'm new to Rust / Rust is new itself and I don't know if this is the best way to express X
  2. I'm waiting for Rust to have feature Y before this library can be complete

contribute to libraries not going 1.0.

3 Likes

But since those projects have been released for a long time, there should be no reason for a 0.x.y-version, even though it means the same as the x.y.z-Version. 0.x version numbers unnecessarily make libraries look immature to me.

People get more mad when something is >1.0 and the public API changes (or even when there's a functionality change/regression, because there's a more general meaning to "break" than the one semver intends but people make assumptions).

People also get mad if you bump the major version too much, even if it's because you're trying to follow semver.

If it's <1.0 and people get mad, you can just say "it's <1.0, I told you."

13 Likes

Well, releasing 1.x.y is a scary thing. It requires commitment to stability of the API and the feature set, and confidence in your library. It means that you are ready for people that are using 1.x for a long time after you've moved to developing 2.x.

Actual version numbers are not relevant here, it's more of a mindset thing. A library that gets 2.x release in a month after 1.x (with 1.x having zero support after that) is not much more mature than a library that just moves on to 0.2.x.

2 Likes

Heck, Cargo itself is central to the Rust ecosystem, and still not 1.0.

4 Likes

It's not surprising how few things are 1.0 at this point. The language itself has been 1.0 for only a bit over a year. The versions numbers on crates feels pretty representative of the ecosystem as a whole. I don't mean this as any kind of slight towards the ecosystem. It's extremely high quality for it's age, but it's still very young.

I think Rust's target audience might play into this too. In my experience, system developers tend to be a pretty prudent bunch when it comes to calling something stable and production ready.

1 Like

It's a bit more complex than that: cargo-the-cli is considered stable. But cargo-as-a-library is not. The version number relates to the latter.

3 Likes

By the way, I recently did some grepping and sorting through the crates.io index, and found the following statistics. This was just for my amusement, so I wasn't super-careful about methodology and may have made some mistakes.

For a crate with multiple versions, my dataset only includes the highest version of that crate.

The median crate's highest version is 0.1.2.

The ten most common highest versions are:

      Count Version
      ----- -------
       1138 "0.1.0"
        817 "0.0.1"
        522 "0.1.1"
        487 "0.2.0"
        286 "0.1.2"
        233 "0.0.2"
        219 "0.3.0"
        174 "0.2.1"
        150 "0.1.3"
        125 "1.0.0" 

Versions of the top ten crates by highest version:

  • 2015.1.7
  • 61.1.0
  • 29.0.0-alpha
  • 9.0.1
  • 7.1.2
  • 7.1.0
  • 6.0.0-2
  • 6.0.0
  • 5.84.0
  • 5.7.0
3 Likes

Aww man, if I'd known there'd be a top ten, I'd have jumped to a higher almost totally arbitrary number than 2.4.0 from 0.1.0 for boolinator...

4 Likes

I've definitely had to fight with the implicit 1.0 decree that "this thing is ready for prime time" but have come to realize that avoiding the full spectrum of semver is generally harmful to the community, since pre-1.0 versions aren't defined by the spec and are treated vastly different by different authors.

I'd encourage package authors to start making major releases early and leave the responsibility of describing the extent of the change (complete rewrite vs small breaking change) to the documentation and release notes, where that information belongs.

There's a really good writeup on this here: Jonathan Ong | Jongleberry

2 Likes

In the Rust ecosystem, 0.x and 0.x+1 are treated as semver incompatible. This isn't part of the semver spec, but it's something you can reasonably rely on if you're using Cargo.

1 Like

You're definitely right here. My point is simply that by committing to 1.0 early, you make it very clear to both end users and tooling that 1.3.0 should continue to be backward-compatible with 1.2.4; conversely, an update to 0.3.0 from 0.2.4 had no compatibility guarantees, and the relationship between API changes and versioning at this level varies quite significantly between authors.

That little article I linked above convinced me quite some time ago that it was OK to go 1.0 even if the final result didn't yet satisfy my OCD/perfectionism :slight_smile:

I've come to terms with seeing big numbers like 12.6.1 on my projects, and agree with the @NeoLegends that the rust ecosystem is a bit cautious in its versioning. In general, my impression of Rust culture is that there is a willingness to experiment but reluctance to commit until an idea or feature is fully vetted (#unstable is a great example of this). This is something I really appreciate, but I do think this mindset contributes to the low version numbers in cargo, which can be unhelpful for the stated reasons.

3 Likes

npm generates packages with 1.0.0 as the default version, and is generally trying to say "0.1 -> 0.2 -> 0.3 is isomorphic to 1.0 -> 2.0 -> 3.0". It was controversial at first, but isn't any more. I'm not saying we should do this, but I'm also not saying we shouldn't.

2 Likes

Similarly, Elm only allows you to publish starting at 1.0.0. They also have some niceties that make that even easier—detecting from the public API changes what kinds of changes are (minimally) needed, which I'd love to see in Cargo at some point—but even apart from that, it's a nice approach.

There are definitely downsides to the Elm approach mentally: it makes it feel harder to experiment and prototype with a published package. At the same time, if you've published a package, you actually already do have the same issue of breaking people with any breaking changes—it's about managing consumer expectations. The pre-1.0 expectation of more breaking changes can help with that, but it has downsides if you get stuck there. If you're de facto stable and widely used and you're at 0.4.0… just ship 1.0.0; the cost to users for a breaking change doesn't suddenly become higher.

2 Likes

Am I the only one who feels this whole thing is a massive waste of time, with everyone just going in circles? You can basically matrix

  • "Version numbers are important, therefore..."
  • "Version numbers are not important, therefore..."

against

  • "...we shouldn't go to 1.0 until we're ready, because users might think the code is more stable than it really is."
  • "...we should go to 1.0 as soon as possible, because users might think code is less stable than it really is."

and come up with a valid position. I mean, people seem to simultaneously hold the belief that version numbers are so important we should start at 1.0, but so unimportant that starting at 1.0 is just as arbitrary as 0.0.

Maybe we should just replace all major version numbers with random words. Then people will stop complaining that crates haven't reached "Badger.0" yet. That way, the legions of users who apparently, for some reason, use totally arbitrary integers as some kind of measure of quality won't have any idea what that means, and thus can't complain about it.

6 Likes

I think a common problem is that you don't know ahead of time if your 0.3 release is completely stable yet. So you publish as 0.3 as you are still experimenting. But then it turns out that there are no more changes. Do you go and change only the version number from 0.3 to 1.0 with no code change? That'll end up causing some builds to fail downstream, as people consider going from 0.3 to 1.0 a breaking change, right?

So you don't want to just bump the version number without having any code change that really warrants it, but because it's been stable, you don't actually have any breaking changes which require a major version bump.

So you just sit at 0.3

If it's a waste of time, then maybe this is just not a thread for you to participate in :slight_smile: Or at least, that's usually how I handle threads that aren't of interest to me.

I agree that in some sense, the fact that people have strong feelings about numbers is a bit arbitrary and can be frustrating, but at the same time, people do feel this way, and just telling them to "stop it" doesn't work. Instead, I'd prefer to find a way to improve things.

After all, if it's truly arbitrary, than the result of this discussion and any changes to it shouldn't matter, right? :wink:

4 Likes