points by mort96 1 day ago

The fundamental problem with Rust versioning is that 0.3.5 is compatible with 0.3.6, but not 0.4.0 or 1.0.0; when major version is 0, the minor takes the role of major and patch takes the role of minor. So packages iterate through 0.x versions, and eventually, they reach a version that's "stable".

If version 0.7 turned out to hit the right API and not require backward incompatible changes, releasing a version 1.0 would be as disruptive as a major version change to your users and communicate through version semantics that it is a breaking change.

Semver declares that version 0.x is for initial development where there is no stability guarantee at all. This is the right semantics for a versioning system, but Cargo doesn't follow this part of semver. Providing stability guarantees throughout the 0.x cycle inevitably results in projects getting stuck in 0.x.

This is one of my biggest gripes with Cargo. But Rust people seem to universally consider it a non-issue so I don't think it'll ever be fixed.

sheepscreek 1 day ago

> The fundamental problem with Rust versioning is that 0.3.5 is compatible with 0.3.6, but not 0.4.0 or 1.0.0

That’s a feature of semver, not a bug :)

Long answer: You are right to notice that minor versions within a major release can introduce new APIs and changes but generally, should not break existing APIs until the next major release.

However, this rule only applies to libraries after they reach 1.0.0. Before 1.0.0, one shouldn’t expect any APIs to be frozen really.

  • mort96 1 day ago

    No, it's explicitly not. Semver says:

    > Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.

    Cargo is explicitly breaking with Semver by considering 0.3.5 compatible with 0.3.6.

    • demurgos 1 day ago

      To go further, semver provides semantics and an ordering but it says nothing about version requirement syntax. The caret operator to describe a range of versions is not part of the spec. It was introduced by initial semver-aware package managers such as npm or gem. Cargo decided to default to the caret operator, but it's still the caret operator.

      In practice, there's no real issue with using the first non-zero component to define the group of API-compatible releases and most package managers agree on the semantics.

      • steveklabnik 1 day ago

        Thank you.

        Eventually this will get cleared up. I’m close than I’ve ever been to actually handling this, but it’s been 9 years already, so what’s another few months…

kibwen 1 day ago

> If version 0.7 turned out to hit the right API and not require backward incompatible changes, releasing a version 1.0 would be as disruptive as a major version change

Nope, this is what the semver trick is for: https://github.com/dtolnay/semver-trick

TL;DR: You take the 0.7 library, release it as 1.0, then make a 0.7.1 release that does nothing other than depend on 1.0 and re-export all its items. Tada, a compatible 1.0 release that 0.7 users will get automatically when they upgrade.

Even more interesting is that you can use this to coordinate only partially-breaking changes, e.g. if you have 100 APIs in your library but only make a breaking change to one, you can re-export the 99 unbroken APIs and only end up making breaking changes in practice for users who actually use the one API with breaking changes.

Starlevel004 1 day ago

The standard library has a whole bunch of tools to let them test and evolve APIs with a required-opt in, but every single ecosystem package has to get it right first try because Cargo will silently forcibly update packages and those evolution tools aren't available to third party packages.

Such a stupid state of affairs.

moron4hire 1 day ago

Personally, I think the 0 major version is a bad idea. I hear the desire to not want to have to make guarantees about stability in the early stages of development and you don't want people depending on it. But hiding that behind "v0.x" doesn't change the fact that you are releasing versions and people are depending on it.

If you didn't want people to depend on your package (hence the word "dependency") then why release it? If your public interface changes, bump that major version number. What are you afraid of? People taking your project seriously?

  • mort96 1 day ago

    Versioning is communication. I find it useful to communicate, through using version 0.x, "this is not a production ready library and it may change at any time, I provide no stability guarantees". Why might I release it in that state? Because it might still be useful to people, and people who find it useful may become contributors.

    • moron4hire 1 day ago

      Any project may change at any time. That's why they bump from v1 to v2. But by not using the full precision of the version number, you're not able to communicate as clearly about releases. A minor release may not be 100% compatible with the previous version, but people still expect some degree of similarity such that migrating is not a difficult task. But going from v0.n to v0.(n+1) uses that field to communicate "hell, anything could happen, YOLO."

      Nobody cares that Chrome's major version is 147.

      • mort96 1 day ago

        By releasing a library with version 1.0, I communicate: "I consider this project to be in a state where it is reasonable to depend on it".

        By releasing a library with version 0.x, I communicate: "I consider this project to be under initial development and would advice people not to depend on in unless you want to participate in its initial development".

        I don't understand why people find this difficult or controversial.

        • steveklabnik 1 day ago

          There is additional subtlety here.

          For example, sometimes projects that have a 0.y version get depended on a lot, and so moving to 1.0.0 can be super painful. This is the case with the libc crate in Rust, which the 0.1.0 -> 0.2.0 transition was super painful for the ecosystem. Even though it should be a 1.0.0 crate, it is not, because the pain of causing an ecosystem split isn't considered to be worth the version number change.

          • mort96 1 day ago

            Oh hey I recently saw a comment which discussed this exact issue: https://news.ycombinator.com/item?id=47752915

            • steveklabnik 1 day ago

              99% of the time this situation is okay, because Cargo allows you to have both 0.1 and 0.2 in the same project as dependencies. It's just packages that call out to external dependencies, like libc, where it enforces the single version rule.

              • mort96 1 day ago

                You can have both 0.1 and 0.2 in the same project, but you really don't want to.

                • steveklabnik 1 day ago

                  Most of the time, it works so well people don't even notice.

                  The only time you run into a problem is if you try and use values with a type from 0.1 with a function that takes a 0.2 as an argument, or whatever. Then you get a type error.

  • jaapz 1 day ago

    0.x is not that you don't want people depending on it, you just don't want them to come and complain when you quickly introduce some breaking changes. The project is still in development, it might be stable enough for use in "real projects(tm)", but it might also still significantly change. It is up to the user to decide whether they are OK with this.

    1.x communicates (to me at least) you are pretty happy with the current state of the package and don't see any considerable breaking changes in the future. When 2.x comes around, this is often after 1.x has been in use for a long time and people have raised some pain points that can only be addressed by breaking the API.

    • moron4hire 1 day ago

      If you are at the point that other people can use your software, then you should use v1. If you are not ready for v1, then you shouldn't be releasing to other people.

      Because this comment, "The project is still in development, it might be stable enough for use in "real projects(tm)", but it might also still significantly change." That describes every project. Every project is always in development. Every project is stable until it isn't. And when it isn't, you bump the major number.

      • the__alchemist 1 day ago

        I think we can come up with a reason why bumping the version number each breaking change isn't an elegant solution either: You would end up with version numbers in the hundreds or thousands.

        • zokier 1 day ago

          Browser version numbers are in the hundreds and it doesn't seem to be a problem.

          • the__alchemist 1 day ago

            Indeed! I think both 0-based versioning, and this (maybe?) downside I bring up addresses the tension between wanting to limit the damage caused by breaking changes with retaining the ability to make them.

    • OtomotO 1 day ago

      But people will complain, so ex falso quodlibet