[Haskell-cafe] The instability of Haskell libraries

John Goerzen jgoerzen at complete.org
Fri Apr 23 14:34:05 EDT 2010


It is somewhat of a surprise to me that I'm making this post, given that 
there was a day when I thought Haskell was moving too slow ;-)

My problem here is that it has become rather difficult to write software 
in Haskell that will still work with newer compiler and library versions 
in future years.  I have Python code of fairly significant complexity 
that only rarely requires any change due to language or library changes. 
  This is not so with Haskel.

Here is a prime example.  (Name hidden because my point here isn't to 
single out one person.)  This is a patch to old-locale:

Wed Sep 24 14:37:55 CDT 2008  xxxxx at xxxxx.xxxx
   * Adding 'T' to conform better to standard
   This is based on information found at
 
http://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations
diff -rN -u old-old-locale/System/Locale.hs new-old-locale/System/Locale.hs
--- old-old-locale/System/Locale.hs	2010-04-23 13:21:31.381619614 -0500
+++ new-old-locale/System/Locale.hs	2010-04-23 13:21:31.381619614 -0500
@@ -79,7 +79,7 @@
  iso8601DateFormat mTimeFmt =
      "%Y-%m-%d" ++ case mTimeFmt of
               Nothing  -> ""
-             Just fmt -> ' ' : fmt
+             Just fmt -> 'T' : fmt

A one-character change.  Harmless?  No.  It entirely changes what the 
function does.  Virtually any existing user of that function will be 
entirely broken.  Of particular note, it caused significant breakage in 
the date/time handling functions in HDBC.

Now, one might argue that the function was incorrectly specified to 
begin with.  But a change like this demands a new function; the original 
one ought to be commented with the situation.

My second example was the addition of instances to time.  This broke 
code where the omitted instances were defined locally.  Worse, the 
version number was not bumped in a significant way to permit testing for 
the condition, and thus conditional compilation, via cabal.  See 
http://bit.ly/cBDj3Q for more on that one.

I could also cite the habit of Hackage to routinely get more and more 
pedantic, rejecting packages that uploaded fine previously; renaming the 
old exception model to OldException instead of introducing the new one 
with a different name (thus breaking much exception-using code), etc.

My point is not that innovation in this community is bad.  Innovation is 
absolutely good, and I don't seek to slow it down.

But rather, my point is that stability has value too.  If I can't take 
Haskell code written as little as 3 years ago and compile it on today's 
platform without errors, we have a problem.  And there is a significant 
chunk of code that I work with that indeed wouldn't work in this way.

I don't have a magic bullet to suggest here.  But I would first say that 
this is a plea for people that commit to core libraries to please bear 
in mind the implications of what you're doing.  If you change a time 
format string, you're going to break code.  If you introduce new 
instances, you're going to break code.  These are not changes that 
should be made lightly, and if they must be made (I'd say there's a 
stronger case for the time instances than the s/ /T/ change), then the 
version number must be bumped significantly enough to be Cabal-testable.

I say this with a few hats.  One, we use Haskell in business.  Some of 
these are very long-term systems, that are set up once and they do their 
task for years.  Finding that code has become uncompilable here is 
undesirable.

Secondly, I'm a Haskell library developer myself.  I try to maintain 
compatibility with GHC & platform versions dating back at least a few 
years with every release.  Unfortunately, this has become nearly 
impossible due to the number of untestable API changes out there.  That 
means that, despite my intent, I too am contributing to the problem.

Thoughts?

-- John


More information about the Haskell-Cafe mailing list