Hacker News new | past | comments | ask | show | jobs | submit login

Not very the parts that make it NP hard are allowing libraries to specify maximum versions (and other more complex version ranges). Most of the time libraries use minimum constraints (~) or (^) which allows the heuristic to work like go's algorithm. For rust, node, and other languages libraries can be imported twice as different versions (without requiring a major version renaming like go) this also allows the heuristic to have an out: if it reaches a really complex case it can just give you both versions. Beyond that package management is a barely disguised 3-SAT solver which we have good, fast solvers. There are definitely some edge cases, but when's the last time you ran any of the following package managers and worried about dependency solve speed? cargo, apt-get, npm (and yarn), dnf, zypper. IO far and away dominates the profiles of these programs, solver speed is basically a non-issue in practice.



does rust have mutable package-level state like go?


It does. There are ways to mark a package as "only once" in the dep graph. For instance, C libraries are required to be marked in this way.

The only once constraint also has a nice out for the SAT solver, if you reach a conflict or something that can't be solved cheaply you just make the user select a version that may not be compatible with the constraints. Bower, dep, and maven work that way.


You anticipated where I was going, which is mutable state + multiple copies of packages seems like a recipe for trouble.

So, I'm not sure how happy I would be as a user if my package installer bailed out and asked me to choose!

Out of curiosity, how do you mark your package as "only once" in cargo? I tried googling, and didn't find an answer, but did find a bug where people couldn't build because they ended up depending on two different versions of C libraries!

It does make wonder if MVS will solve real pain in practice. :-)


> So, I'm not sure how happy I would be as a user if my package installer bailed out and asked me to choose!

Its definitely not a great UX, but at the end of the day the problem can only be solved at the language level or by package authors choosing new names. For instance in java you can't import 2 major versions of a package. Solving for minor versions having to bail out has been incredibly rare in my experience. I only see it when there's "true" incompatibilities, e.g.

foo: ^1.5.0 bar: foo (<= 1.5)

> Out of curiosity, how do you mark your package as "only once" in cargo? I tried googling, and didn't find an answer, but did find a bug where people couldn't build because they ended up depending on two different versions of C libraries!

I think its the `links = ""` flag. It may only work for linking against C libraries at the moment, but cargo understands it!

> It does make wonder if MVS will solve real pain in practice. :-)

Not by itself, the semantic import versioning is the solution to the major version problem, by giving major versions of package different names. Go packages aren't allowed to blacklist versions, though your top level module is. This just means that package authors are going to have to communicate incompatible versions out of band, and that the go tool may pick logically incompatible versions with no signal to the user beyond (hopefully) broken tests!


> Go packages aren't allowed to blacklist versions, though your top level module is. This just means that package authors are going to have to communicate incompatible versions out of band, and that the go tool may pick logically incompatible versions with no signal to the user beyond (hopefully) broken tests!

Yeah, it seems if the Go system ends up not working out in practice, this will be why.

But because of the minimal nature of MVS, you won't run into this problem unless something else is compelling you to go to the broken version. And by the time that's happening, you'd hope that the bug would've been reported and fixed in the original library.

It'll be interesting to see how it plays out in practice.

(Also, if I have a library A that depends on B, which is being reluctant or slow about fixing some bug, I can always take the nuclear option and just fork B and then depend on that. Basically the explicit version of what Cargo would do through deciding it couldn't resolve w/o creating two versions. But I think the incentives might be set up right that the easy/happy path will end up getting taken in practice.)


Packages are made up of modules, and modules can have global state. But doing so directly is unsafe, specifically because it can introduce a data race. Rust also does not have “life before main”, so it doesn’t get used in the same way as languages that do. I’m not sure if Go does?


Even if its not just "mutable" state there are a lot of undesirable situations for multiple package imports in rust:

1. Singletonish things like global allocators, rayon-core, etc

2. You may have made a package static safe to mutate with a mutex, but it could be a bad thing to have different versions of that mutex.

3. Compile time computed tables (unicode table, perfect hashes, etc) could be imported multiple times ballooning the binary.

4. ABI/type compatibility with any reexported types


Oh totally. Thanks for listing those out.


(I replied but the reply vanished. If it reappears, apologies for the dup.)

Yeah, go has a magic function `func init()` which gets called before main. (You can actually have as many init's as you want, and they all get called.)

Probably evil, though so far it hasn't hurt me in the same way as, e.g., c++ constructors have. Maybe because it's more explicit and thus you're less likely to use it in practice.


Cool, thanks!




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: