3 ms·
Rust has a nice semver-based package management tool called cargo. One thing rust/cargo does really well is packaging up different versions of the same dependen
by adastra22 2y ago
Rust has a nice semver-based package management tool called cargo. One thing rust/cargo does really well is packaging up different versions of the same dependency for the same build. E.g. your project can update to widget=2.0 while some of your downstream dependencies are still stuck on the 1.x release branch. Cargo's semver support means that those dependencies can be automatically upgrade to support newer 1.x releases, but they will not work with 2.x without the package maintainer's intervention. In the mean time it just compiles and links to both, while keeping them isolated.
Usually this is great. You avoid dependency hell while only trading off some compiled binary size. Sometimes it fails when a package must have only one version, e.g. because you're passing around data types from that package to/from your dependencies which use the old version, but part of rust/cargo's trick is that types drawn from different versions of the same package are distinct types. So you get a compile-time type check error.
Solution: the widget package maintainer pushes out a final 1.x release which itself depends on widget=2, and is simply a shim that re-exports the API. This semver-violating trickery is basically a stealth upgrade that forces all upstream widget=1 pegged crates onto the new widget=2 release branch.
This trick is generic and relevant outside of rust, at least so far as other package managers user semver-aware dependency management.
- deleted 2y ago[deleted]
- wakawaka28 2y agoI think I get how this works but other package managers would likely solve the problem by specifying that the v2 package "provides" the v1 interface, and then possibly deprecating or removing v1. At least I think that would work. It's not something I've sought to do. Most libraries in C or C++ do not support linkage of different versions in one app, so you must pick exactly one version to run with.
- Tuna-Fish 2y agoThe problem with this is that v2 by definition does not provide the v1 interface, or there would be no reason to bump up the major version number. Using the trick, the last v1 package is a facade that constructs the old interface using the new package. To provide equivalent functionality, you basically have to do the same thing.
- wakawaka28 2y agoOK then if you want to keep the v1 interface exactly then you have to build a facade yourself. I don't think most libraries are capable of supporting that use case because of their semantic structure. Instead of employing a bunch of tricks to avoid fixing a couple of functions (the case where a facade makes sense), you should just fix the callers. That might not be easy for packages that are independently published (for example pypi or cargo packages) but it is possible in many package managers that have central teams of maintainers.
- adastra22 2y agoThe whole thing is sus. If widget=2 can work as a drop-in replacement (non-breaking) for widget=1, then why the version bump in the first place? But in the real world there are times when major versions are bumped without breaking changes. E.g. a bunch of crates maintained as part of a single project with a uniform versioning scheme.
- wakawaka28 2y agoI think now there must be some kind of adapter code, even if auto-generated, that is a facade from v1 to v2. You can essentially use that to release a new v1 minor revision that depends on v2 for its implementation. But yeah the whole thing sounds sus, not easily applicable to other languages (where does this adapter code come from and how does it coexist with v2?), and like a bad practice even when it can work. You should really just migrate everyone to the new version instead of patching together something to handle stubborn users of the old version.