[Haskell-cafe] Platform Versioning Policy: upper bounds are not our friends
Twan van Laarhoven
twanvl at gmail.com
Thu Aug 16 14:42:15 CEST 2012
On 16/08/12 14:07, Chris Smith wrote:
> As a package author, when I
> release a new version, I know perfectly well what incompatible changes
> I have made to it... and those might include, for example:
>
> 1. New modules, exports or instances... low risk
> 2. Changes to less frequently used, advanced, or "internal" APIs...
> moderate risk
> 3. Completely revamped commonly used interfaces... high risk
Would adding a single convenience function be low or high risk? You say it is
low risk, but it still risks breaking a build if a user has defined a function
with the same name. I think the only meaningful distinction you can make are:
1. No change to public API at all, user code is guaranteed to "compile and
work if it did so before".
Perhaps new modules could also fall under this category, I'm not sure.
2. changes to exports, instances, modules, types, etc. But with the guarantee
that "if it compiles, it will be correct"
3. changes to functionality, which require the user to reconsider all code.
"even if it compiles, it might be wrong"
For the very common case 2, the best solution is to just go ahead and try to
compile it.
> A. Cabal files should get a new "Compatibility" field, indicating the
> level of compatibility from the previous release: low, medium, high,
> or something like that, with definitions for what each one means.
You would need to indicate how large the change is compared to a certain
previous version. "Moderate change compared to 0.10, large change compared to 0.9".
> B. Version constraints should get a new syntax:
>
> bytestring ~ 0.10.* (allow later versions that indicate low or
> moderate risk)
> bytestring ~~ 0.10.* (allow later versions with low risk; we use
> the dark corners of this one)
> bytestring == 0.10.* (depend 100% on 0.10, and allow nothing else)
>
> Of course, this adds a good bit of complexity to the constraint
> solver... but not really. It's more like a pre-processing pass to
> replace fuzzy constraints with precise ones.
>
Perhaps it would be cleaner if you specified what parts of the API you depend
on, instead of an arbitrary distinction between 'internal' and 'external' parts.
From cabal's point of view the best solution would be to have a separate
package for the internals. Then the only remaining distinction is between
'breaking' and 'non-breaking' changes. The current policy is to rely on major
version numbers. But this could instead be made explicit: A cabal package should
declare what API version of itself it is mostly-compatible with.
To avoid forcing the creation of packages just for versioning, perhaps
dependencies could be specified on parts of a package?
build-depends: bytestring.internal ~< 0.11
and the bytestring package would specify what parts have changed:
compatibility: bytestring.internal >= 0.11, bytestring.external >= 0.10
But these names introduce another problem: they will not be fine-grained enough
until it is too late. You only know how the API is partitioned when, in the
future, a part of it changes while another part does not.
Twan
More information about the Haskell-Cafe
mailing list