[Haskell-cafe] The instability of Haskell libraries
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
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
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.
More information about the Haskell-Cafe