The fact that packages are uniquely identified (1) is perhaps the only constraint that makes sense for all common dependency systems. But for the rest of the constraints, they are all inadequate for some common real-world dependency systems. For example, it's possible to have dependency systems where order is not required for versions (2). In such systems, dependencies must be specified with exact sets of compatible versions, and bounded ranges make no sense. Being able to uniquely define the successor of any version (3) is also a constraint that is not a natural fit if versions have a system of pre-releases. Indeed, what is the successor of 2.0.0-alpha? We can't tell if that is 2.0.0 or 2.0.0-beta or 2.0.0-whatever. Having fixed dependencies (4) is also not followed in programming languages allowing optional dependencies. In Rust packages, optional dependencies are called "features" for example. Finally, restricting solutions to only one version per package (5) is also too constraining for dependency systems allowing breaking changes. In cases where packages A and B both depend on different ranges of package C, we sometimes want to be able to have a solution where two versions of C are present, and let the compiler decide if their usages of C in the code are compatible.