[Haskell-cafe] Would you use frozen-base
Joachim Breitner
mail at joachim-breitner.de
Thu Feb 26 13:36:11 UTC 2015
Hi,
= Introduction (can be skipped) =
Recently, I find myself often worried about stability of our ecosystem –
may it be the FTP discussion, or the proposed¹ removal of functions you
shouldn’t use, like fromJust. While all that makes our language and base
libraries nicer, it also means that my chances that code from 3 or 4
years ago will compile without adjustment on newer compilers are quite
low.
Then I remember that a perl based webpage that I wrote 12 years ago just
keeps working, even as I upgrade perl with every Debian stable release,
and I’m happy about that. It makes me wonder if I am ever going to
regret using Haskell because there, I’d have to decide whether I want to
invest time to upgrade my code or simply stop using it.
I definitely do not want to stop Haskell from evolving. Maybe we can
make a more stable Haskell experience opt-in? This is one step in that
direction, solving (as always) only parts of the problem.
= The problem =
One problem is that our central library "base" is both an implementation
and an interface. As the implementation is tied to the compiler, and the
interface comes with the implementation, you cannot upgrade one without
the other.
= My solution: frozen-base =
My solution would be to provide a new library, let’s call it
frozen-base, which decouples the interface (frozen-base) from the
implementation (still base).
We would start with one particular version of base, say, 4.6. With
GHC-7.6 (which comes with base 4.6), frozen-base would simply re-export
its modules². On newer compilers and newer versions of base, it would
re-create the old interface using CPP. So if your program depends on
frozen-base only, you can expect it to compile with newer versions of
GHC – achievement unlocked.
= How to get new features, then? =
But does that mean that you do not get to use great new functionality in
later versions of base, such as Data.Bool.bool? No: When a new version
of base gets released, and a module gets changed, than frozen-base will
ship a _new_ module, named
Data.Bool1
that matches that interface. The next change in base causes yet another
module to be created, i.e.
Data.Bool2
So if you need to use Data.Bool.bool, in one of your modules, you simply
change the import from "import Data.Bool" to "import Data.Bool2", adjust
your code to the new interface, and are ready to go. Note that you only
had to adjust to the changes in Data.Bool, nothing else. Note that you
also had to touch only a single module in your program, the others still
use whatever interface they were using.
Your dependency on frozen-base would have to indicate a lower version
bound, i.e. specify the lowest version that has all the Data.Bool<n>
variants that you desire, but – by design – never an upper version.³
= When does it not work? =
Of course, the promises by froze-base are not absolute: There are
changes in base that frozen-base cannot protect you against: Data type
changes, some type class changes, type class instances. I don’t have any
great ideas here, but maybe they are rare enough so that frozen-base is
still useful.
= What about the Prelude? =
I did not talk about the Prelude. There probably is not a good solution,
and I’d simply leave the Prelude frozen. Maybe later GHC has a nice way
to specifying which Prelude to use in a certain module, then you could
use "Prelude1", "Prelude2" etc. in the same manner.
= How does it related to base-compat? =
The idea is similar to what base-compat provides, but the other way
around: base-compat allows you to use the latest features of base on
older compilers, while frozen-base would allow you to use the API of old
base versions on newer systems.
Frozen-base might subsume base-compat by providing, say Data.Bool2 with
the API from base-4.8 also on systems with base-4.6.
= How does it related to the split base proposal =
Depending on how exactly base is being reconstructed, it might become a
pure interface package on its own, or at least independent from
compiler-specific bits. Then it might be feasible that, say, after the
release of ghc-7.10 there is a new upload of base-4.6.0.n that provides
the 4.6 API, but compiles on ghc-7.10. This way, if you depend on
base == 4.6.*
you could still expect your program to work. If that happens, and also
cabal would learn that a plan with different versions of a interface
only library like base are not a problem, frozen-base might be
obsoleted.
See https://ghc.haskell.org/trac/ghc/wiki/SplitBase for more on that.
= No Conclusion and lots of future work =
So what do you think? Would you be interested in using this? Do you have
reasons to believe that this will not work as nicely as I think i could?
Greetings,
Joachim
¹ but rejected, it seems
² or a sensible subset; I could imagine not exporting certain .Internal
modules and things like OldTypeable that are about compatibility
themselves.
³ or just one on the very major version number (frozen-base < 2), which
to allow for exceptional breaking changes – a redesign of the module
naming scheme for example.
--
Joachim “nomeata” Breitner
mail at joachim-breitner.de • http://www.joachim-breitner.de/
Jabber: nomeata at joachim-breitner.de • GPG-Key: 0xF0FBF51F
Debian Developer: nomeata at debian.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20150226/1e51cab8/attachment.sig>
More information about the Haskell-Cafe
mailing list