Roman Leshchinskiy wrote:
IMO, a package is absolutely the wrong thing to depend on. Essentially,
a package is an implementation of an interface and depending on
implementations is a bad thing. Code should only depend on interfaces
which are completely independent entities. I suspect that a lot of the
problems with packages occur because the current system doesn't follow
this simple principle.
It would be nice if Cabal had an explicit concept of interfaces, with
the idea that code depends on them and packages implement them. In the
simplest case, an interface is just a name. Ideally, it would be a
combination of type signatures, Quickcheck properties, proof obligations
etc. The important thing is that it has an explicit definition which is
completely independent of any concrete implementation and which never
changes.
Something like this would immediately solve a lot of problems. Several
packages could implement the same interface and we could pick which one
we want when building stuff. We could have much more fine-grained
dependencies (if all I need is an AVL tree, I don't want to depend on
the entire containers package, but rather just on the AVL part of it).
One package could implement several versions of an interface to ensure
compatibility with old code (I could imagine module names like
AVL_1.Data.AVLTree, AVL_2.Data.AVLTree etc., where AVL_1 and AVL_2 are
interface names; Cabal could then map the right module to Data.AVLTree
when building). If interface definitions include something like
Quickcheck properties, we would have at least some assurance that a
package actually does implement its interfaces. Moreover, this would
also make the properties themselves reusable.
We already have interfaces, in the sense that a package *is* an interface.
You're suggestion decoupling these notions, which I believe would add a
lot of extra complexity without enough benefit to make it worthwhile.
Let's take the examples you gave above:
1. several packages could implement the same interface. This can be done
by having a single package that exports an interface and depends on one of
the underlying "providers" selected at build-time.
2. fine-grained dependencies: just split up packages, or define new
packages that just re-export parts of existing packages, if that's what you
want.
3. one package could implement several versions of an interface. This is
no different from having several versions of a package that can all be
installed and used together.
4. interface definitions could have QuickCheck properties. Absolutely!
And packages can have QuickCheck properties too.
Admittedly in order to do most of this we need to be able to define
packages that re-export the contents of other packages. You can in fact
already do this, but it's clumsy, we just need some tool and compiler
support to make it smoother. I'm already convinced that we need this, and
I believe we should do it in the GHC 6.10 timeframe in order to allow
better backwards compatibility.
Using the Package Versioning Policy we have a clear way to know when a
package's interface has changed, or when the interface has remained the
same but the implementation has changed. We need tool support to check
that the author is adhering to the PVP, though.
Basically the current scheme minimizes the cognitive load by having a
single concept (the package) that embodies several units: distribution,
licensing, dependency, linking (amongst others).
Cheers,
Simon
_______________________________________________
cabal-devel mailing list
cabal-devel@haskell.org
http://www.haskell.org/mailman/listinfo/cabal-devel