4 ms·
I have never really thought about this problem before, but would it not be possible to: 1. Treat each version of a package as a separate package. If there are
by d_theorist 11y ago
I have never really thought about this problem before, but would it not be possible to:
1. Treat each version of a package as a separate package. If there are two versions required, they are both included.
2. At compile time transform package names to include the desired version number.
I may be completely misunderstanding or over-simplifying this problem.
- lostcolony 11y agoFor some things, yes. But there are a lot of potentially tricksy issues in doing that. Imagine a queueing library, for instance. You push something onto a queue created with library A, and then you want to read from library B (A and B are different version of the same library). Just about anything could happen (depending on how the library/language are implemented). You might get an error due to library B reading a data structure formatted for library A. Or you might get nothing back, because library B is checking for the queue in its own registry, while it exists in library A's. Etc. If there is no library-dependent state between calls, or the calls are not being mixed between libraries, you can totally do that, though. A JSON serialization library can totally be supported in that manner, for instance. The queueing library example, if it's only being used to support other libraries or separate functionalities, such that you never have to push onto a queue in library A, and expect to be able to pop it off from a queue in library B, would work, too. But in that latter case, that's not something the library writer can guarantee, it's all about your own usage. So there's a lot of potential issues.
- pcwalton 11y agoMaking the version part of the type generally fixes these issues. Anything that could go wrong will nearly always go wrong at compile time.
- ustolemyname 11y agoSure, that fixes some problems, but I don't understand how that would solve the first example listed above. Can you explain how the compiler would prevent this runtime error? // package a lib-v16.Queue(int32) // Stores in queue for version 16 of lib // package b int32 = lib-v18.DeQueue() // Loads from queue of version 18 of lib, which is empty And even if we accept that you shouldn't have state in the package and the queue should be passed around, now we just have two packages (a & b) that use incompatible versions of lib for potentially no reason.
- pcwalton 11y agoThat is a theoretical problem, yes. In practice I've never seen it be an issue, because (a) global state is frowned upon and (b) packages that depend on each other so tightly tend to have dependencies at the type level, making the probability that such errors slip past the compiler very low. To expand on (b), suppose that packages A and B depend on a shared queue managed by package C, as in your example. Because A and B have such tightly coupled logic, chances are that some package--either one of A and B, or some other package that depends on A and B--will have code that expects a type from "A's C" to be equivalent to a type from "B's C". At that point the code will fail to compile, and the programmer will fix the problem before it ever hits production. (Fixing this is easy because you can just inspect the lockfile to find all the crate versions in use.) Basically, static typing makes it such that, while the problem exists in theory, in practice its probability is so low as to not be a concern.
- wtetzner 11y agoIt catches the error, but doesn't solve the problem, because now you can't write the program you intended to write.
- pcwalton 11y agoSure you can. Just run cargo update [-p] to get both of your dependencies on the same version and then recompile. This won't work if the dependencies are truly depending on incompatible-at-the-API-level versions of the same library, of course. But there's no magic bullet solution to that—not handling versioning in the language/package manager doesn't make that problem any easier.
- wtetzner 11y agoAh, so we're on the same page :). I definitely wasn't claiming Go's (non-)solution was the way to go, just that importing multiple versions of the same library doesn't solve the problem either. I definitely agree with you that this (Rust/Cargo's) is the best solution I've seen so far.
- pcwalton 11y agoYes, that is essentially what systems like Rust/Cargo do. It works great.