
On 26-02-2015 14:36, Joachim Breitner wrote:
Hi, [--snip--]
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.
Having actually worked with code using this approach to versioning, I think I can safely say that it is absolute hell in practice -- way worse than sprinkling a few CPP directives here and there. Granted, in my particular case data structures were also versioned thusly, and so you'd end up with reams of boilerplate (but only sometimes boilerplate!) Bool1<->Bool2 conversion code. Similar problems would ensue if semantics of Foo1.frobnicate() and Foo2.frobnicate() were subtly different, but you'd happened to call the wrong one. Not to mention all the namespace pollution if you need to access both Foo1 and Foo2 in the same module. There's also the mental overhead of having to be aware of all the Foo1, Foo2, ... modules and the differences between them. (There's probably a lot more pain that I've just repressed, but that's just off the top of my head.) The proper solution to this problem (as with so many things) is another layer of indirection, namely a proper way to separate API and implementation. (Aka "Backpack" or similar.) Regards,