3 ms·
Not knowing rust, this is pretty meaningless to me. Is this trick relevant outside of rust?
by tantalor 2y ago
Not knowing rust, this is pretty meaningless to me.
Is this trick relevant outside of rust?
- Xylakant 2y agoTheoretically, it can be. However, it’s only relevant in specific circumstances that Rust happens to provide, for example one of the requirements is that the package manager / build system allows you to have two different versions of the same dependencies in a single binary - which is comparatively rare.
- jerf 2y agoI've used something very similar in Go. I can't point to it because it's an internal repository, but it allowed for relatively smooth co-existence between a v1 and a v2 of a particular package that had one aspect that was hard-to-upgrade, but also, generally rarely used compared to the rest. The rest of the types were fully identical because v1 simply re-exported the v2 types, so Go only complains if you try to cross the streams with the specifically-changed but rarely-used types, which is exactly the complaint I want. In the case of Go I'm not sure if it's important that v1 specifically re-export the v2; I think it would work equally well either way. But it's at least very similar.
- adastra22 2y agoRust 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.
- clhodapp 2y agoThis feels like something similar would almost be relevant in Java Platform Modules, since modules also have the ability to re-export classes that they've imported. However, there are some small limitations that would make it annoying to adopt this pattern: Having more than one version of the same classname available in different modules requires boilerplate and it's difficult to define over some of the classes of a module that your module imports.
- edflsafoiewq 2y agoIt's relevant to any kind of dependency graph. Essentially it's converting A A / \ / \ Cv2 B into | B \ \ \ Cv1 \ Cv1 \ / Cv2 Suppose some exported symbol, X, didn't change from Cv1 to Cv2. In the former, A gets two copies of X depending on which path it took up the dependency tree. In the latter, there's only one copy since both paths terminate in the same place.