To me, the motivation for specifying exact dependencies as much a social concern as a technical one - it puts responsibility, or blame, where it belongs. If we take an example scenario for "bad packaging", something like:

* developer X releases package A, version 1.0

* developer Y releases package B, version 1.0, depending on package A > 1.0

* developer X releases package A version 1.1 with breaking changes

* user Z with package A 1.1 installed attempts to build package B and fails

Who is to blame in this case? At first thought you'd blame developer X for releasing breaking changes without bumping up the major version, however, there was nothing in his "contract" that says he cannot do this - moreover, even if one specified up front that they will "not release breaking changes without bumping the major version", how can you even enforce that at the software level?

The way we actually model the "blame" in the industry is to blame Z - the idiot user who can't build software, who failed to follow incorrect documentation and feels like an idiot because he doesn't know what was wrong - then he wastes significant time searching for solutions, debugging build scripts, re-versioning the dependencies by introducing A10 and A11 in place of A, because he needs both, and his PM can't have two of the same name, and the names can't contain periods (Arbitrary restriction of some PMs).

The actual blame here lies in Y - he is the one who documented that his software will work with any version of A greater than 1.0, but I find this declaration to be idiotic - he cannot possibly uphold this "contract", because he is not in control of A. The best guarantee he can give is "I've tested this with 1.0, but it may work with any later version, however, do so at your own risk."

Ok, so there's no really a "contract" to be held - particularly for public domain works and "permissive" licensed works where the developer is just giving stuff away for free, but in the case of copyleft works - such as the GPL, it specifically requires that you distribute all of the scripts required to build the software. While perhaps not a violation of the license in the legal sense - releasing build scripts which simply don't work is a violation of the spirit of the GPL.

We could argue that "may work with any later version" is precisely what we mean with "> 1.0", but it confuses me as to why anyone would think releasing an untested build script would ever work - you would never release software into production without first testing it. Releasing a package with a dependency that doesn't yet exist cannot possibly be tested - it's not fit for production. If a developer has tested a piece of software with all dependency versions between 1.0 and 2.0, and decides they all work successfully, then I see this as the only real case where ranged versions are acceptable - except in this case you have a set of exact dependencies tested against which could be used instead of the range, so why not specify dependencies as a set?

These complaints are not specific to any language semantics - it's just a case of untested code being unreliable, and tested code, where all the "tests" are encoded into the definition of the software (thereby removing the "hidden knowledge" that goes into building it), is close to perfectly reliable - any failure to reproduce was probably beyond the control of a package publisher anyway (although when we have ReproducibleBuilds, this should never happen.)

> That's a large ball of complexity and dependencies. It isn't clear that that's actually a more effective solution than just rolling a package manager for each language.

As I stated, LSPMs are an incomplete solution - they don't provide the complete "dependency resolution" which we expect from a PM. If we take for example, I release a Cabal package for Cairo bindings in Haskell, and I run "cabal install Cairo", what actually happens?

If I'm lucky, a compatible (by magic) version of native cairo is installed, and it builds fine. If Cairo is not installed, it will fail with some cryptic message saying ExitFailure 1, something or other about gtkhs-buildtools. If I'm an expert already I can wave my magic wand and fix the problem, otherwise I'm googling a solution. Turns out the problem is simple in this case, I don't have the package "cairo-dev" installed on my OS, and I need to install it manually through another PM, say, apt.

But then this defeats the purpose - the LSPM, Cabal, has failed at dependency resolution - it can't resolve Cairo because it's beyond its scope - having Cairo on the system is the responsibility of the system PM (which is really an LSPM where the specific language is C, etc).

The point here is to eliminate the need for manual installation of cairo - by providing the means for Cabal and apt to talk - Cabal can simply ask "do you have cairo", to which it can reply "yes", or "no, would you like me to install it", or "no, go away".

This may not be such a concern in dart, since you don't really have bindings to native libraries.

I don't see how this is a large ball of complexity, but I think it could reduce it. As things stand, some LSPMs attempt to somehow resolve native dependencies through ad-hoc means, by looking for them in specific locations in the filesystem, or by dumping the native dependencies into the project folder itself (good luck picking up bug-fixes and making portable projects this way). Other LSPMs simply shut down and cry when you need a native dependency, "it's not my problem".

Rather than trying bridge individual PMs on an ad-hoc basis, it would make more sense to come up with the right abstraction/verbs for them to talk - and each one have an adapter to a global "package manager manager daemon",. This would be like "QUERY cairo", "INSTALLED", "NOT INSTALLED", etc. (As I said, I don't have all of the details, as that would require a large social effort.)

The reason the Nix model would be required for this kind of collaboration of PMs should be obvious - if I query "cairo", is it going to ask apt to install cairo, or ask Cabal to install cairo? It can't possibly guess without the user disambiguating - adding version numbers here can't help either. The only solution here is to make sure there can be no ambiguity between them - different names won't work because the different package managers have distinct repositories managed by separate communities. The solution is an identity, hash-based, or based on a cryptographic signature - it's required for any kind of security if we were to have PMs talk to each other - however, using hash based identities, we can treat the knowledge of the hash as a capability, and if two different package managers (such as apt and yum) provided the same package identity, it wouldn't matter which one performed the installation, because it's the same capability.

I'm not trying to find the "One True Package Semantics", but rather, create an environment where each PM can handle its own niche, but bridge the gap that's missing where they simply stop working - by having some kind of shared language between them.