4 ms·
Except that a shit-ton of developers will code and test with one version of a dependency, and never, ever, ever update it. If the dependency has a catastrophic
by Hizonner 5y ago
Except that a shit-ton of developers will code and test with one version of a dependency, and never, ever, ever update it. If the dependency has a catastrophic security hole, that security hole will be pretty much permanent.
And what happens if project A pins projects B and C, which in turn pin DIFFERENT versions of project D? Is there any language or environment out there that can make that work?
- howdydoo 5y agoRead it again. Any one dependency, or the root project, has the power to pull in the latest version. One laggard dependency does not stop that. For your second question, yes, Rust handles that well. If you depend on ">=1.0" and ">=1.1", you end up with a single copy of 1.1. If you depend on "=1.0" and "=1.1", you end up with both copies of the library. Every crate uses the version it requested. You can argue whether that's good or bad, but at least it's principled. There's a lint if you dislike that behavior. https://rust-lang.github.io/rust-clippy/master/#multiple_crate_versions https://rust-lang.github.io/rust-clippy/master/#multiple_cra...
- Hizonner 5y agoOK, so suppose I depend on anarchy, which wants shades >=1.0.1, and chaos, which wants shades >=1.0.2. The author of shades releases 1.0.3 because of a bad security hole in all prior versions. My project will still get 1.0.2, so it will still have the security hole. For that matter, it may ALSO break because anarchy is broken by a change made between shades 1.0.1 and 1.0.2... which is why the maintainer of anarchy hasn't updated their dependency. On the whole, I think I'd prefer a solver that gave me 1.0.3 by default (but maybe would NOT give me 2.0.0 by default, depending on what the version numbers mean in this particular system). But the bottom line is that there is NO solver that can be SURE that what I eventually get will really work. That's an interesting fact about Rust, and I didn't know it. On the whole, it sounds like it at least needs some serious tooling so you can make sure you're not dragging in a bunch of old versions that both bloat your code and open you to abuse. Can I ask for a warning if I'm getting two different versions linked into the same binary? If something depends on "=1.0", and the maintainer issues 1.1 with a flag that says "I really, really don't think think you should be using 1.0 any more", will that throw an error? And what happens if both versions get pulled in, but the package in question uses an external data file whose format changed between 1.0 and 1.1? Edited to change "<=" to ">="...
- Hizonner 5y agoOh, and another Rust question, if you don't mind. If I have both versions 1.0 and 1.1 of package X in my binary, and X defines a data type called foo, and one of my dependencies constructs a foo using X 1.0, is that value of a different type than a foo constructed by X 1.1? Or can version 1.0 foos wind their way through the code and up being processed by version 1.1 code?
- howdydoo 5y ago> My project will still get 1.0.2, so it will still have the security hole. Right. To mitigate that you would regularly run `npm audit` or even just `npm upgrade` – and test afterwards of course. I'm not completely sold, but I do think it's a very interesting idea. > Can I ask for a warning if I'm getting two different versions linked into the same binary? Yes. That was the lint I linked in my last post. Alternatively, you can run `cargo tree --duplicates`. > "I really, really don't think think you should be using 1.0 any more" That's called "yanking". Personally I think it has limited usefulness, but it exists. https://doc.rust-lang.org/cargo/commands/cargo-yank.html https://doc.rust-lang.org/cargo/commands/cargo-yank.html > And what happens if both versions get pulled in, but the package in question uses an external data file whose format changed between 1.0 and 1.1? If it uses something like `include!`, both copies will be compiled in (and maybe optimized later by the linker). If it's truly "external" like hosted on some website outside the package manager, then it just means the author broke their package. Maybe I misunderstood your question. > one of my dependencies constructs a foo using X 1.0, is that value of a different type than a foo constructed by X 1.1? I believe they are always different types. Cargo encourages but doesn't enforce semver, so anything can change between versions, including private fields or enum variants behind non_exhaustive, etc. So they're treated as different and you need to convert between them. Although this might only be true for major versions; I don't know off the top of my head. To work around it you can convert the types at crate boundaries, or the package author can use the so-called "semver trick" [1] [1]: https://github.com/dtolnay/semver-trick https://github.com/dtolnay/semver-trick
- Hizonner 5y ago
- littlestymaar 5y ago> For your second question, yes, Rust handles that well. If you depend on ">=1.0" and ">=1.1", you end up with a single copy of 1.1. If you depend on "=1.0" and "=1.1", you end up with both copies of the library. Every crate uses the version it requested. IIRC rust only does that for MAJOR versions (1.1 and 2.0, or 0.2 and 0.3, since cargo consider releases before 1.0.0 to be major ones).
- remram 5y agoTo clarify, if you depend on ">=1.0" and ">=1.1", you might also end up with a single copy of 1.2. Rust does not implement the "maximum version" scheme described above.
- jessaustin 5y agoAnd what happens if project A pins projects B and C, which in turn pin DIFFERENT versions of project D? Is there any language or environment out there that can make that work? Node and npm have always been able to do this. Once upon a time this was accomplished via very hierarchical node_modules directories. This caused some issues, so the directory was flattened, however the multi-version compatibility was always maintained.