Specifying dependencies on Haskell code
marlowsd at gmail.com
Mon May 12 07:04:34 EDT 2008
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
> 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
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).
More information about the Libraries