Re:Rust Solved Dependency Hell
by moring on Thursday July 18, 2019 @06:00AM
(#20468284)
Java has a very similar solution to the problem using OSGi. It uses class loaders to encapsulate sets of classes to isolate them and also uses the class loader for disambiguation.
Compare the solutions: "It seems there's four basic components incorporated in a mangled symbol name:"
* "The fully qualified name of the symbol." -- same in Java
* "Generic type parameters." -- missing in Java because of type erasure
* "The name of the crate containing the symbol." -- represented by the class loader in Java
* "An arbitrary “disambiguator” string" -- not present in Java, and I'm not sure why this is needed at all
It even comes with almost the same downsides: "This solution isn't perfect though:"
* "...we can't pass objects around between different versions of a library" -- similar with OSGi (you can pass objects using the opaque "Object" type), but you might be able to have libraries agree on a common interface, defined by an "API library", which has the same version for both and allows to pass objects.
* "Any static variables or global state will be duplicated" -- same with OSGi
* "Our binary size increases necessarily" -- same with OSGi
Re:Rust Solved Dependency Hell
by wst_ on Thursday July 18, 2019 @07:28AM
(#20468664)
Even without OSGi there are plugins allowing so called package names shadowing and, as a consequence, for multiple versions of the same dependency coexist in the same classpath. Rust, though, have this as a part of the language. This is a whole new level of user (or developer in that case) experience.
Re:Rust Solved Dependency Hell
by mshroyer on Thursday July 18, 2019 @12:59AM
(#20466862)
(Not a Rustacean yet.)
Are there any circumstances in which this approach can have undesirable behavior, for example if the dependency has to deal with some global state?
This seems like the kind of thing that could create difficult-to-understand problems if Cargo gives you two copies of a dependency only under specific and rare circumstances. (But I'm happy to be proven wrong, and I'm sure the Rust folks have thought this through more carefully than I have.)
Re:Rust Solved Dependency Hell
by zaarn on Thursday July 18, 2019 @03:46AM
(#20467680)
That is actually a fairly recent addition. I wasted like 2 days of my time trying to find the bug until someone pointed out it could be differing versions of the crate.
Re:Rust Solved Dependency Hell
by babyloneleven on Thursday July 18, 2019 @07:07AM
(#20468561)
The rayon crate has a global state: the entire program must use the same thread pool, even if different crates depend on different rayon versions.
It uses a Cargo feature meant to be used by native libraries: you typically can link them only once (or else the build will fail when it finds repeated symbols), so Cargo must ensure only one is present on the entire dependency graph. And IIRC Rayon depends on an auxiliary crate that fakes a native lib and provides the thread pool.
If this seems very hacky and convoluted, it's because it is.
Re:Rust Solved Dependency Hell
by bjorn2k on Thursday July 18, 2019 @03:10AM
(#20467488)
If you rely on global state, this global state is also mangled to a different symbol, this might be undesirable.
For example, if you use a logger which relies on a extern defined variable. Your singleton is duplicated.
Also all your code is duplicated.
I agree that how rust does it is a very nice solution.
Re:Rust Solved Dependency Hell
by ameliaquining on Sunday July 21, 2019 @08:06PM
(#20494512)
I think it's still NP-complete because you can still specify arbitrary dependency constraints. (Of course, just because it's NP-complete doesn't mean it's not tractable in practice for the kinds of instances that come up in real life.)
Re:Rust Solved Dependency Hell
by nwmcsween on Thursday July 18, 2019 @07:12AM
(#20468580)
Version strings are sort of a hack, while it does communicate API breakage, etc it doesn't communicate what. Given a language with an effect system and powerful enough type system you could verify for input x result is y and store it as a hashed sym alias, etc
Re:Rust Solved Dependency Hell
by iamcreasy on Thursday July 18, 2019 @11:13AM
(#20470650)
I thought you can have different version of the same library for different parts of the project in Java, but didn't know about the non deterministic behavior about which one to use. I wonder how Gradle handles this situation.
Re:Rust Solved Dependency Hell
by _nhynes on Thursday July 18, 2019 @01:32AM
(#20467001)
Basically. Cargo is so good that the only things I could possibly wish for are specifying binary dependencies and easier use of Cargo as a library (and maybe a more robust `patch` section, but there's always `paths` in .cargo/config).
Compare the solutions: "It seems there's four basic components incorporated in a mangled symbol name:"
* "The fully qualified name of the symbol." -- same in Java
* "Generic type parameters." -- missing in Java because of type erasure
* "The name of the crate containing the symbol." -- represented by the class loader in Java
* "An arbitrary “disambiguator” string" -- not present in Java, and I'm not sure why this is needed at all
It even comes with almost the same downsides: "This solution isn't perfect though:"
* "...we can't pass objects around between different versions of a library" -- similar with OSGi (you can pass objects using the opaque "Object" type), but you might be able to have libraries agree on a common interface, defined by an "API library", which has the same version for both and allows to pass objects.
* "Any static variables or global state will be duplicated" -- same with OSGi * "Our binary size increases necessarily" -- same with OSGi
(edit: formatting)
Are there any circumstances in which this approach can have undesirable behavior, for example if the dependency has to deal with some global state?
This seems like the kind of thing that could create difficult-to-understand problems if Cargo gives you two copies of a dependency only under specific and rare circumstances. (But I'm happy to be proven wrong, and I'm sure the Rust folks have thought this through more carefully than I have.)
It uses a Cargo feature meant to be used by native libraries: you typically can link them only once (or else the build will fail when it finds repeated symbols), so Cargo must ensure only one is present on the entire dependency graph. And IIRC Rayon depends on an auxiliary crate that fakes a native lib and provides the thread pool.
If this seems very hacky and convoluted, it's because it is.
I agree that how rust does it is a very nice solution.
Need random numbers? Then you need this create. Is it first party or written by some random dude? Hard to tell.