
On the topic of cabal odisseys: I think it would help to document (prominently) what Cabal fundamentally doesn't (try to) do, to avoid optimistic expectations (and hence the surprises when Cabal doesn't meet those expectations), and to point out the design choices behind many bug tickets (even if the choices are temporary and driven by limited manpower). Such as - cabal doesn't keep track of what it installs, hence - no uninstall - no application tracking - library tracking and information about installed library configurations only via ghc-pkg .. - cabal's view of package interfaces is limited to explicitly provided package names and version numbers, hence - no guarantee that interface changes are reflected in version number differences - no detailed view of interfaces (types, functions, ..) - no reflection of build/configure options in versions - no reflection of dependency versions/configurations in dependent versions - no knowledge of whether dependencies get exposed in dependent package interfaces .. This is just to demonstrate the kind of information I'd like to see - Duncan&co know the real list, though they don't seem to have it spelled out anywhere? So users see that it works to say "cabal install" and build up their own often optimistic picture of what (current) Cabal is supposed to be able to do. It might even be useful to have a category of "core-tickets" or such on the trac, to identify these as work-package opportunities for hackathons, GSoC and the like, positively affecting many tickets at once. On to the specific issue at hand:
2. cabal ought to allow using multiple versions of a single package in more circumstances than it does now .. 2. This is a problem of information and optimisitic or pesimistic assumptions. Technically there is no problem with typechecking or linking in the presense of multiple versions of a package. If we have a type Foo from package foo-1.0 then that is a different type to Foo from package foo-1.1. GHC knows this.
So if for example a package uses regex or QC privately then other parts of the same program (e.g. different libs) can also use different versions of the same packages. There are other examples of course where types from some common package get used in interfaces (e.g. ByteString or Text). In these cases it is essential that the same version of the package be used on both sides of the interface otherwise we will get a type error because text-0.7:Data.Text.Text does not unify with text-0.8:Data.Text.Text.
The problem for the package manager (i.e. cabal) is knowing which of the two above scenarios apply for each dependency and thus whether multiple versions of that dependency should be allowed or not. Currently cabal does not have any information whatsoever to make that distinction so we have to make the conservative assumption. If for example we knew that particular dependencies were "private" dependencies then we would have enough information to do a better job in very many of the common examples.
My preference here is for adding a new field, build-depends-private (or some such similar name) and to encourage packages to distinguish between their public/visible dependencies and their private/invisible deps.
This private/public distinction should be inferred, or at least be checked, not just stated. I don't know how GHC computes its ABI hashes - are they monolithic, or modular (so that the influence of dependencies, current package, current compiler, current option settings, could be extracted)? Even for monolithic ABI hashes, it might be possible to compute the package ABI hash a second time, setting the versions of all dependencies declared to be private to 0.0.0 and seeing if that makes a difference (if it does, the supposedly private dependency leaks into the package ABI, right?). And secondly, how about making it possible for cabal files to express sharing constraints for versions of dependencies? To begin with, there is currently no way to distinguish packages with different flag settings or dependency versions. If I write a package extended-base, adding the all-important functions car and cdr to an otherwise unchanged Data.List, that package will work with just about any version of base (until car and cdr appear in base:-), but the resulting packages may not be compatible, in spite of identical version numbers. If it was possible to refer to those package parameters (build options and dependency versions), one could then add constraints specifying which package parameters ought to match for a build configuration to be acceptable. Let us annotate package identifiers with their dependencies where the current lack of dependency and sharing annotations means "I don't care how this was built". Then build-depends: a, regex means "I need a and regex, but I don't care whether a also uses some version of regex", while build-depends: a, regex sharing: a(regex)==regex would mean "I need any version of a and regex, as long as a depends on same the version of regex I depend on" (choose any syntax that works). And build-depends: a, b sharing: a(text)==b(text) would mean "I need any version of a and b, as long as they both depend on the same version of text". I can already think of situations where one might want more complex constraints (e.g. "I want any version of base and mtl, but either both have to be before the Either-move, or both have to be after the move" - this part could be expressed already, but there is currently no way to enforce this transitively, for dependencies, so if I depend on c, which depends on a new base, and on d, which depends on an old mtl, I'm out of luck, I think). Or: "never mix mtl and its alternatives". Of course, this scheme depends on whether it is possible to reverse engineer the information about dependencies of installed packages from ghc-pkg info or ABI hashes.. but if the general idea is sound, perhaps that could be made possible? Just a suggestion, Claus