Stop untracked dependencies! (was RE: mapping module identifiers to URLs (was RE: [Haskell] URLs in haskellmodule namespace))

S. Alexander Jacobson alex at
Thu Mar 31 14:06:57 EST 2005

A major problem in every major language I have ever used is module 
systems that make it all too easy for untracked dependencies to creep 
silently into code.  The result has repeatedly been nasty surprises 
when moving code between machines.  A Haskell example of this problem 
might look something like this:

* Oh, Network.HTTP is non-standard!? Thats wierd.
* Uh Oh. Google reveals at least three different implementations...
* Now, how do I determine which one is installed here?
* Is there a local copy of the package somewhere?
* No? Ok, is it available for download somewhere?
* Uhm, is the version I am using still available for download?
* Oh, we made local changes too!? What were they?
* Ok, we added Network.Socket.SSL. That's standard right? [rinse/repeat]
[A lot of detective work later...]
* Ok, now we've figured out all the packages, how do we ship them?
[shipping strategy devised...]
* But what happens if I don't have root/admin on the target machine? [...]
* Oh, this package conflicts with something already installed? [etc.]

> It is true that Cabal's Build-Depends doesn't do everything you want it
> to, but your proposal also duplicates some of the functionality of
> Build-Depends, and makes it so that there are two places where
> dependencies are stored. We should only have to specify 
> dependencies once.

I agree you should only have to specify dependencies once.  But, 
deferring dependency tracking to the point you are ready to ship (with 
Cabal or otherwise) is a recipe for disaster.  Every code dependency 
should be explicit and verified at compile time. You should be able to 
to look at any block of code at any time and be able to produce the 
list of packages required to make it run.

Strawman proposal 2:

   Modify the import syntax to allow package identifiers:

    import qualified HaXML HaXML.XML.Parse
    import HAppS HAppS.ACID
    import Personal MyLib

   Define a packages file format to resolve package ids to locations:

      <package id="HaXML" src="">
        <remap ref="HUnit" src=""/>
        <remap ref="Parse" src="#Parse"/>
      <package id="Parse" src=""/>
      <package id="HAppS" src="" />
      <package id="Personal" src="../MyLibs" />
      <redirect from="http://oldversion" to="http://newversion" />

   Add a -p option to the compiler pointing to a packages file
   and use the content of that file to resolve module ids to
   implementations.  The compiler MUST give an error if the user tries
   to associate the same module id with two different implementations
   [no grafting/module relativity!]

   Remove the -i compiler option.  Any import of a module not
   in the local path must have a package id.  [Get rid of import path
   order/overlap ambiguity!]

   Replace Cabal's Build-Depends field label with a Packages field
   label that takes a path to a packages file as a value.  Add option
   to include a copy of all packages used by the current package.

   Give error if modules from other packages give conflicting module
   implementations.  Allow user to resolve conflict in imported package
   files by using remap and redirect elements in the packages file.

> I don't think it's necessary to specify dependencies with module
> granularity.  This just increases the number of possible error cases,
> without adding functionality.

If I use multiple packages that export the same module identifier, I 
need a way to specify which one I want to use.  Haskell's existing 
packaging model doesn't let met do that easily.

>   - Package dependencies in Build-Depends could be specified using
>     URLs.

But then dependencies aren't checked at compile time and you can't 
specify which modules come from which packages.

>   - Cabal could download, build, and install dependencies without any
>     user intervention.

Download and build? Great!  Install? No thank you!

In a fundamental sense, *installation* of third party libraries is 
exactly what I am opposing here.  Library installation is what allows 
untracked dependencies to creep in.  Users of executables definitely 
want a process for installation of executables in their local 
environment because they need a way to adjudicate potential conflicts 
between them (e.g. file associations).  However, what users of 
libraries want is just a safe and easy way to populate a local cache 
of module-implementations from various sources and that is what I am 
asking for here.


S. Alexander Jacobson tel:917-770-6565

More information about the Haskell mailing list