3 ms·
One thing that's often not mentioned is - how to deal with experimental APIs and such? You don't want to mark them as experimental indefinitely, and you don't w
by o11c 3y ago
One thing that's often not mentioned is - how to deal with experimental APIs and such? You don't want to mark them as experimental indefinitely, and you don't want to force an upgrade if the experimental API didn't change when stabilizing.
The best solution I've found is: each compiled library doesn't just have a single API, but rather has multiple.
libfoo-1.2.3 might implement the following APIs:
* libfoo-1.0
* libfoo-1.1
* libfoo-1.2
* libfoo-1.2.1 (because people don't actually use the "no API additions in patch releases" rule)
* libfoo-1.2.2
* libfoo-1.2.3
* libfoo-experimental-1_2_3 (no semver in the version here)
and if you enable experimental exports for the library, you gain a package-manager-level dependency on libfoo-experimental-1_2_3. Then later you can declare "libfoo-1.3 includes libfoo-experimental-1_2_3", so old programs can use newer libraries without change.
That said, mutable metadata is still an important part of the ecosystem. Blacklisting is essential (since the symbol-list isn't actually the whole API and it is impossible to automatically detect violations), but easily abused for "that's insecure" and "I don't support that" purposes so there should be some friction.
Note also that ABI (and sometimes API) is fundamentally platform-specific. And there's enough complexity in the world that the tooling shouldn't think in terms of semver, but rather arbitrary compatibility DAGs (but with sparseness when possible). Consider the GCC 4.7.0/4.7.1 std::list breakage that was reverted in 4.7.2, breaking software that was compiled in the mean time (the only reason this wasn't catastrophic is because nobody actually uses std::list) - that intermediate software needs to know it can't use new binaries.
- obi1kenobi 3y agoIn Rust, this is often done by using optional features, and usually features named like `unstable-<something>`. They are a form of conditional compilation: people that don't opt in don't see that code, and people that do opt in know the code is unstable. `cargo-semver-checks` by default doesn't check for any semver obligations for code behind such features. (I'm its maintainer )
- epage 3y agoAnd we'd like to have native support for these in cargo: https://github.com/rust-lang/cargo/issues/10881 https://github.com/rust-lang/cargo/issues/10881
- o11c 3y agoThe problem with the current approach is that it does not specify whether `libfoo-1.2.3[unstable-bar]` is compatible with `libfoo-1.3.4[unstable-bar]`, nor whether the latter is compatible with `libfoo-1.4.5[default]`. (also I'm not sure under what circumstances recompilation is required)
- conradludgate 3y agoThe rust std lib doesn't make any commitments to unstable (nightly) APIs, so this is the norm.
- o11c 3y agoIt doesn't formally make commitments. But in practice for most particular APIs there is stability, and it is the job of tooling to support that.