[Haskell-cafe] Platform Versioning Policy: upper bounds are not our friends

150 переглядів
Перейти до першого непрочитаного повідомлення

Bryan O'Sullivan

не прочитано,
15 серп. 2012 р., 15:38:3315.08.12
Кому: haskel...@haskell.org
Hi, folks -

I'm sure we are all familiar with the phrase "cabal dependency hell" at this point, as the number of projects on Hackage that are intended to hack around the problem slowly grows.

I am currently undergoing a fresh visit to that unhappy realm, as I try to rebuild some of my packages to see if they work with the GHC 7.6 release candidate.

A substantial number of the difficulties I am encountering are related to packages specifying upper bounds on their dependencies. This is a recurrent problem, and its source lies in the recommendations of the PVP itself (problematic phrase highlighted in bold):

When publishing a Cabal package, you should ensure that your dependencies in the build-depends field are accurate. This means specifying not only lower bounds, but also upper bounds on every dependency.

I understand that the intention behind requiring tight upper bounds was good, but in practice this has worked out terribly, leading to depsolver failures that prevent a package from being installed, when everything goes smoothly with the upper bounds relaxed. The default response has been for a flurry of small updates to packages in which the upper bounds are loosened, thus guaranteeing that the problem will recur in a year or less. This is neither sensible, fun, nor sustainable.

In practice, when an author bumps a version of a depended-upon package, the changes are almost always either benign, or will lead to compilation failure in the depending-upon package. A benign change will obviously have no visible effect, while a compilation failure is actually better than a depsolver failure, because it's more informative.

This leaves the nasty-but-in-my-experience-rare case of runtime failures caused by semantic changes. In these instances, a downstream package should reactively add an upper bound once a problem is discovered.

I propose that the sense of the recommendation around upper bounds in the PVP be reversed: upper bounds should be specified only when there is a known problem with a new version of a depended-upon package.

Johan Tibell

не прочитано,
15 серп. 2012 р., 15:57:4315.08.12
Кому: Bryan O'Sullivan, haskel...@haskell.org
On Wed, Aug 15, 2012 at 12:38 PM, Bryan O'Sullivan <b...@serpentine.com> wrote:
> I propose that the sense of the recommendation around upper bounds in the
> PVP be reversed: upper bounds should be specified only when there is a known
> problem with a new version of a depended-upon package.

This argument precisely captures my feelings on this subject. I will
be removing upper bounds next time I make releases of my packages.

-- Johan

_______________________________________________
Haskell-Cafe mailing list
Haskel...@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Brandon Allbery

не прочитано,
15 серп. 2012 р., 16:02:1815.08.12
Кому: Johan Tibell, haskel...@haskell.org
On Wed, Aug 15, 2012 at 3:57 PM, Johan Tibell <johan....@gmail.com> wrote:
On Wed, Aug 15, 2012 at 12:38 PM, Bryan O'Sullivan <b...@serpentine.com> wrote:
> I propose that the sense of the recommendation around upper bounds in the
> PVP be reversed: upper bounds should be specified only when there is a known
> problem with a new version of a depended-upon package.

This argument precisely captures my feelings on this subject. I will
be removing upper bounds next time I make releases of my packages.

So we are certain that the rounds of failures that led to their being *added* will never happen again?

--
brandon s allbery                                      allb...@gmail.com
wandering unix systems administrator (available)     (412) 475-9364 vm/sms

Bryan O'Sullivan

не прочитано,
15 серп. 2012 р., 16:15:5815.08.12
Кому: Brandon Allbery, haskel...@haskell.org
On Wed, Aug 15, 2012 at 1:02 PM, Brandon Allbery <allb...@gmail.com> wrote:

So we are certain that the rounds of failures that led to their being *added* will never happen again?

Of course I am sure that problems will arise as a result of recommending that upper bounds be added reactively; didn't I say as much? I expect that to be a much lesser problem than the current situation.

Johan Tibell

не прочитано,
15 серп. 2012 р., 16:44:1115.08.12
Кому: Brandon Allbery, Duncan Coutts, haskel...@haskell.org
On Wed, Aug 15, 2012 at 1:02 PM, Brandon Allbery <allb...@gmail.com> wrote:
> So we are certain that the rounds of failures that led to their being
> *added* will never happen again?

It would be useful to have some examples of these. I'm not sure we had
any when we wrote the policy (but Duncan would know more), but rather
reasoned our way to the current policy by saying that things can
theoretically break if we don't have upper bounds, therefore we need
them.

David Thomas

не прочитано,
15 серп. 2012 р., 16:50:5415.08.12
Кому: Johan Tibell, Duncan Coutts, haskel...@haskell.org

Would it make sense to have a known-to-be-stable-though soft upper bound added proactively, and a known-to-break-above hard bound added reactively, so people can loosen gracefully as appropriate?

Bryan O'Sullivan

не прочитано,
15 серп. 2012 р., 16:55:0015.08.12
Кому: David Thomas, Duncan Coutts, haskel...@haskell.org
On Wed, Aug 15, 2012 at 1:50 PM, David Thomas <davidle...@gmail.com> wrote:

Would it make sense to have a known-to-be-stable-though soft upper bound added proactively, and a known-to-break-above hard bound added reactively, so people can loosen gracefully as appropriate?

I don't think so. It adds complexity, but more importantly it's usual for the existing upper bounds to refer to versions that don't exist at the time of writing (and hence can't be known to be stable).

Michael Blume

не прочитано,
15 серп. 2012 р., 17:04:0415.08.12
Кому: Bryan O'Sullivan, Duncan Coutts, haskel...@haskell.org
> it's usual for the existing upper bounds to refer to versions that don't exist at the time of writing (and hence can't be known to be stable).

Well, known to be stable given semantic versioning, then.

http://semver.org/

Carter Schonwald

не прочитано,
15 серп. 2012 р., 17:34:5315.08.12
Кому: Michael Blume, Bryan O'Sullivan, Duncan Coutts, haskell-cafe
As someone who recurrently is nudging a large number of maintainers every major ghc release to bump their bounds, I favor the no upper bounds approach! :)

plus the whole improving ecosystem of build bot tools which play nice with cabal et al that are cropping up mean that "in principal" we could debug missing upper bounds via sort of temporal bisecting over the "event stream" of maximum available versions at a given time to sort that. (but that piece isn't that important)

more pragmatically, cabal when used with hackage doesn't let you override version constraints, it just lets you add additional constraints. This makes sense if we assume that the library author is saying "things will definitely break if you violate them", but in practice upper bounds are made up guesstimation. 

YES, its presumably semantic versioning doesn't create a problem, but with the hackage eco system, when dealing with intelligently engineering libs that are regularly maintained, version upper bounds create more problems than than solve.

just my two cents. (yes yes yes, please drop upper bounds!)

cheers
-Carter

Lorenzo Bolla

не прочитано,
15 серп. 2012 р., 17:47:2915.08.12
Кому: haskel...@haskell.org
I definitely agree!
http://www.reddit.com/r/haskell/comments/x4knd/what_is_the_reason_for_haskells_cabal_package/

L.
> _______________________________________________
> Haskell-Cafe mailing list
> Haskel...@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe


--
Lorenzo Bolla
http://lbolla.info

Brandon Allbery

не прочитано,
15 серп. 2012 р., 17:44:4615.08.12
Кому: Johan Tibell, Duncan Coutts, haskel...@haskell.org
On Wed, Aug 15, 2012 at 4:44 PM, Johan Tibell <johan....@gmail.com> wrote:
On Wed, Aug 15, 2012 at 1:02 PM, Brandon Allbery <allb...@gmail.com> wrote:
> So we are certain that the rounds of failures that led to their being
> *added* will never happen again?

It would be useful to have some examples of these. I'm not sure we had

Upper package versions did not originally exist, and nobody wanted them.  You can see the result in at least half the packages on Hackage:  upper versions came in when base got broken up, and when bytestring was merged into base --- both of which caused massive breakage that apparently even the people around at the time and involved with it no longer remember.

I'm not going to argue the point though; ignore history and remove them if you desire.

Carter Schonwald

не прочитано,
15 серп. 2012 р., 18:46:1115.08.12
Кому: Brandon Allbery, Duncan Coutts, haskel...@haskell.org
no one is disputing that there are conditional changes in dependencies depending on library versions. 

an interesting intermediate point would be have a notion of "testing with " constraints in cabal and engineering cabal to support a "--withTestedConstraints" to have a simple composable way of handling constructing build plans.

at the end of the day, its an engineering problem coupled with a social factors problem. Those are hard :)


Michael Sloan

не прочитано,
15 серп. 2012 р., 18:54:0415.08.12
Кому: Carter Schonwald, Duncan Coutts, haskell-cafe
Upper bounds are a bit of a catch-22 when it comes to library authors evolving
their APIs:

1) If library clients aren't encouraged to specify which version of the
exported API they target, then changing APIs can lead to opaque compile
errors (without any information about which API is intended). This could
lead the client to need to search for the appropriate version of the
library.

If library clients are encouraged to specify which versions of the
exported API they target,
then changing the API breaks all of the clients.

There are a couple of hacky ways to do #1 without having the errors be so opaque

1) Start a tradition of commenting the cabal dependencies with the version of
the package that worked for the author.

2) Build in support for these "known good" versions into cabal, perhaps
generated on "sdist"release, or with a particular build flag. (they don't
need to be stored in the .cabal file)

3) Attempt to post-process GHC error messages to guess when the issue might be
caused by the package version being different according to the PVP. This
could work alright for scoping but wouldn't work well for type errors
(which matter more)

I like the idea of doing automated upper-bound-determination! That would be
very convenient. It's a bit tricky though - should tests be included?

I think the most ideal solution is to attack the core problem: things break
when dependencies change their interface. This is pretty expected in the
development world at large, but I think that Haskell can do better.

The main idea is that package developers should be free to update their API as
they realize that new names or interfaces are better. Currently there's the
problem that the APIs that actually get used subsequently stagnate due to fear
of breakage.

The solution that I think makes the most sense is to start exporting modules
which express the old interface in terms of the new. What's interesting about
this is that most non-semantic changes to things other than ADTs and
typeclasses can already be expressed in plain Haskell code.

This idea, among other things, inspired the "instance templates" proposal,
which is somewhat related to superclass default instances. With this language
extension, it would be possible to express compatibility layers for instance
definitions, something that is impossible with Superclass Default Instances.

https://github.com/mgsloan/instance-templates

I've also got a start on a utility for extracting API signatures from
packages. Currently it just pretty prints the API in a fashion that attempts
to be amenable to textual diffing:

https://github.com/mgsloan/api-compat/
https://github.com/mgsloan/api-compat/blob/master/examples/diagrams-core.api.diff

The intent is to make the tool interactive, giving the user a chance to let
the tool know which exports / modules have been renamed. After the user
provides this information, it should be possible to generate almost all of the
compatibility code.

In order to make it convenient to use these compatibility modules, we'd want
to have some cabal- invoked code generation that would generate proxy modules
that re-export the appropriate version. This could all happen in a separate
hs-source-dir.

The next step in this toolchain is something that's very hard to do nicely,
because it can change code layout: automated rewriting of user code to target
the new version (this is equivalent to "inlining" the compatibility module
definitions). However, even a tool that would take you to all of the
places that
need changing would be invaluable.

Wouldn't it be excellent, if the Haskell eco-system managed something that no
other language affords?:

* Automatic refactoring to target new API versions

* Expression of these refactorings in the language itself

* Rigorous, structured documentation of inter-version changes. This'd also
provide a nice place to put haddocks with further change information.

-Michael

Brandon Allbery

не прочитано,
15 серп. 2012 р., 18:55:0315.08.12
Кому: Carter Schonwald, Duncan Coutts, haskel...@haskell.org
On Wed, Aug 15, 2012 at 6:46 PM, Carter Schonwald <carter.s...@gmail.com> wrote:
no one is disputing that there are conditional changes in dependencies depending on library versions. 

Indeed.  But the ghc release that split up base broke cabalised packages with no warning to users until they failed to compile.  Upper bounds were put in place to avoid that kind of breakage in the future.

Ivan Lazar Miljenovic

не прочитано,
15 серп. 2012 р., 21:19:0315.08.12
Кому: Brandon Allbery, Duncan Coutts, haskel...@haskell.org
On 16 August 2012 08:55, Brandon Allbery <allb...@gmail.com> wrote:
> On Wed, Aug 15, 2012 at 6:46 PM, Carter Schonwald
> <carter.s...@gmail.com> wrote:
>>
>> no one is disputing that there are conditional changes in dependencies
>> depending on library versions.
>
>
> Indeed. But the ghc release that split up base broke cabalised packages
> with no warning to users until they failed to compile. Upper bounds were
> put in place to avoid that kind of breakage in the future.

There's also the case where people blindly put something like "base <
10" in the .cabal file, and then it broke on the next GHC release.
This happend with ghc-core-0.5: it completely failed to build with
base-4 (and because cabal-install kept defaulting packages to use
base-3 I think a lot of people missed cases like this and blindly
thought it worked).

I like having upper bounds on version numbers... right up until people
abuse them.

--
Ivan Lazar Miljenovic
Ivan.Mi...@gmail.com
http://IvanMiljenovic.wordpress.com

Conrad Parker

не прочитано,
15 серп. 2012 р., 22:38:2715.08.12
Кому: Bryan O'Sullivan, haskel...@haskell.org
On 16 August 2012 03:38, Bryan O'Sullivan <b...@serpentine.com> wrote:
> Hi, folks -
>
> I'm sure we are all familiar with the phrase "cabal dependency hell" at this
> point, as the number of projects on Hackage that are intended to hack around
> the problem slowly grows.
>
> I am currently undergoing a fresh visit to that unhappy realm, as I try to
> rebuild some of my packages to see if they work with the GHC 7.6 release
> candidate.

Likewise ...

> A substantial number of the difficulties I am encountering are related to
> packages specifying upper bounds on their dependencies. This is a recurrent
> problem, and its source lies in the recommendations of the PVP itself
> (problematic phrase highlighted in bold):

I think part of the problem might be that some packages (like
bytestring, transformers?) have had their major version number
incremented even despite being backwards-compatible. Perhaps there are
incompatible changes, but most of the cabal churn I've seen recently
has involved incrementing the bytestring upper bound to <0.11 without
requiring any code changes to modules using Data.ByteString.

IMO it'd be better to include a separate versioning entry like
libtool's version-info, consisting of Current:Revision:Age
(http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html),
and leave the published "version" for human, marketing purposes.

I remember discussing this with Duncan at ICFP last year, and he
suggested that the existing PVP is equivalent to the libtool scheme in
that the major release should only be incremented if
backwards-compatibility breaks.

However I think people also expect to use the published version as a
kind of marketing, to indicate that the project has reached some
milestone or stability, or is part of some larger, separately
versioned group of packages (eg. new compiler or platform release).
The PVP pretty much ensures that incrementing a major version for such
reasons is going to break your package for all its users.

Conrad.

MightyByte

не прочитано,
15 серп. 2012 р., 23:02:0015.08.12
Кому: Ivan Lazar Miljenovic, Haskell Cafe
On Wed, Aug 15, 2012 at 9:19 PM, Ivan Lazar Miljenovic
<ivan.mi...@gmail.com> wrote:
> On 16 August 2012 08:55, Brandon Allbery <allb...@gmail.com> wrote:
>> Indeed. But the ghc release that split up base broke cabalised packages
>> with no warning to users until they failed to compile. Upper bounds were
>> put in place to avoid that kind of breakage in the future.
>
> I like having upper bounds on version numbers... right up until people
> abuse them.

I also tend to favor having upper bounds. Obviously they impose a
cost, but it's not clear to me at all that getting rid of them is a
better tradeoff. I've had projects that I put aside for awhile only
to come back and discover that they would no longer build because I
hadn't put upper bounds on all my package dependencies. With no upper
bounds, a package might not be very likely to break for incremental
version bumps, but eventually it *will* break. And when it does it's
a huge pain to get it building again. If I have put effort into
making a specific version of my package work properly today, I want it
to always work properly in the future (assuming that everyone obeys
the PVP). I don't think it's unreasonable that some activation energy
be required to allow one's project to work with a new version of some
upstream dependency.

Is that activation energy too high right now? Almost definitely. But
that's a tool problem, not a problem with the existence of upper
bounds themselves. One tool-based way to help with this problem would
be to add a flag to Cabal/cabal-install that would cause it to ignore
upper bounds. (Frankly, I think it would also be great if
Cabal/cabal-install enforced upper version bounds automatically if
none were specified.) Another approach that has been discussed is
detecting dependencies that are only used internally[1], and I'm sure
there are many other possibilities. In short, I think we should be
moving more towards purely functional builds that reduce the chance
that external factors will break things, and it seems like removing
upper version bounds is a step in the other direction.

[1] http://cdsmith.wordpress.com/2011/01/21/a-recap-about-cabal-and-haskell-libraries/

Brandon Allbery

не прочитано,
15 серп. 2012 р., 23:34:5215.08.12
Кому: MightyByte, Ivan Lazar Miljenovic, Haskell Cafe
On Wed, Aug 15, 2012 at 11:02 PM, MightyByte <might...@gmail.com> wrote:
be to add a flag to Cabal/cabal-install that would cause it to ignore
upper bounds.  (Frankly, I think it would also be great if

Ignore, or at least treat them as being like flags... if the versions don't converge with them, start relaxing them and retrying, then print a warning about the versions it slipped and attempt the build.

That said, I'd be in favor of moving toward something based on ABI versioning instead; package versions as used by the PVP are basically a manual switch emulating that.  It's not generally done because other parts of the toolchain (notably ld's shared object versioning) don't support it, but given that Cabal has greater control over the build process for Haskell programs it would be worth exploring having Cabal deal with it.  (This is not something you can do with existing C or C++ toolchains; the smarts would need to be in make.)

Michael Snoyman

не прочитано,
16 серп. 2012 р., 01:01:5516.08.12
Кому: Conrad Parker, haskel...@haskell.org
On Thu, Aug 16, 2012 at 5:38 AM, Conrad Parker <con...@metadecks.org> wrote:
On 16 August 2012 03:38, Bryan O'Sullivan <b...@serpentine.com> wrote:
> Hi, folks -
>
> I'm sure we are all familiar with the phrase "cabal dependency hell" at this
> point, as the number of projects on Hackage that are intended to hack around
> the problem slowly grows.
>
> I am currently undergoing a fresh visit to that unhappy realm, as I try to
> rebuild some of my packages to see if they work with the GHC 7.6 release
> candidate.

Likewise ...

> A substantial number of the difficulties I am encountering are related to
> packages specifying upper bounds on their dependencies. This is a recurrent
> problem, and its source lies in the recommendations of the PVP itself
> (problematic phrase highlighted in bold):

I think part of the problem might be that some packages (like
bytestring, transformers?) have had their major version number
incremented even despite being backwards-compatible. Perhaps there are
incompatible changes, but most of the cabal churn I've seen recently
has involved incrementing the bytestring upper bound to <0.11 without
requiring any code changes to modules using Data.ByteString.


In general, I've been taking the approach recently that we have two classes of packages: some (like transformers and bytestring) have mostly-stable APIs, and most code I write only relies on those APIs. If I'm just using Data.ByteString for the ByteString type and a few functions like readFile and map, it's highly unlikely that the next version will introduce some breaking change. In those cases, I've been leaving off the upper bound entirely.

For other packages that haven't yet stabilized, I've still been keeping the upper bound. In many cases, even that isn't necessary. I've tried removing the upper bounds on those as well, but I almost always end up getting someone filing a bug report that I left off some upper bound and therefore a compile failed.

I agree with Bryan's argument, but I'd like to keep consistency for most packages on Hackage. If the community goes in this direction, I'll go along too.

Michael

Daniel Trstenjak

не прочитано,
16 серп. 2012 р., 03:56:2816.08.12
Кому: Michael Sloan, haskell-cafe

On Wed, Aug 15, 2012 at 03:54:04PM -0700, Michael Sloan wrote:
> Upper bounds are a bit of a catch-22 when it comes to library authors evolving
> their APIs:
>
> 1) If library clients aren't encouraged to specify which version of the
> exported API they target, then changing APIs can lead to opaque compile
> errors (without any information about which API is intended). This could
> lead the client to need to search for the appropriate version of the
> library.

Having the version number A.B.*, than most packages seem to mostly
increase B or lower parts of the version number.

If an upper bound is missing, than cabal could use any package in the range A.*.* .

If an author wants to make breaking changes to his API, than he could
indicate this by increasing A.

I've nothing against your proposal, I just don't think that it will be
done that soon.


Greetings,
Daniel

Joachim Breitner

не прочитано,
16 серп. 2012 р., 04:45:4616.08.12
Кому: haskel...@haskell.org
Hi,

Am Mittwoch, den 15.08.2012, 12:38 -0700 schrieb Bryan O'Sullivan:
> I propose that the sense of the recommendation around upper bounds in
> the PVP be reversed: upper bounds should be specified only when there
> is a known problem with a new version of a depended-upon package.

as a Debian packager, I kinda like the tight upper bounds, as it allows
me to predict what packages will break when I upgrade package X. It is
only an approximation, but a safe one. If we would not have this, then I
would either
* upgrade X, upload to Debian, start rebuilding other stuff (this
is automated and happens on Debians build servers), notice a
break in package Y and then have to wait for Y’s upstream author
to fix it. All the while, Y and all its reverse dependencies
would not be installable. If this collides with a freeze, we’d
be in big trouble.
* upgrade X locally, rebuild everything manually and locally and
only if thinks work out nicely, upload the whole bunch. Would
work, but would be a huge amount of extra work.
(note that in Debian we have at most one version of each Haskell
package).


I think what we’d need is a more relaxed policy with modifying a
package’s meta data on hackage. What if hackage would allow uploading a
new package with the same version number, as long as it is identical up
to an extended version range? Then the first person who stumbles over an
upper bound that turned out to be too tight can just fix it and upload
the fixed package directly, without waiting for the author to react.

If modifying packages with the same version number is not nice (it does
break certain other invariants), we could make it acceptable behavior to
upload someone else’s package without asking provided
* one bumps the last (forth) component of the version
* one extends the version range to encompass a set of versions
that the uploader has just tested to work _without changes_
* no other change to the tarball is done.

This way, the common user of hackage (including us distro packagers)
will likely get a successful build if the build dependencies are
adhered, but new version will much quicker work everywhere, even when
original authors are temporarily slow to react.

More power to everyone! Be bold! :-)

Greetings,
Joachim

--
Joachim "nomeata" Breitner
ma...@joachim-breitner.de | nom...@debian.org | GPG: 0x4743206C
xmpp: nom...@joachim-breitner.de | http://www.joachim-breitner.de/

signature.asc

Ketil Malde

не прочитано,
16 серп. 2012 р., 06:50:1616.08.12
Кому: Bryan O'Sullivan, haskel...@haskell.org
"Bryan O'Sullivan" <b...@serpentine.com> writes:

> I propose that the sense of the recommendation around upper bounds in the
> PVP be reversed: upper bounds should be specified *only when there is a
> known problem with a new version* of a depended-upon package.

Another advantage to this is that it's not always clear what constitutes
an API change. I had to put an upper bound on binary, since 0.5
introduced laziness changes that broke my program. (I later got some
help to implement a workaround, but binary-0.4.4 is still substantially
faster). Understandably, the authors didn't see this as a breaking API
change.

So, +1.

-k
--
If I haven't seen further, it is by standing in the footprints of giants

Chris Smith

не прочитано,
16 серп. 2012 р., 08:07:1716.08.12
Кому: haskel...@haskell.org
I am tentatively in agreement that upper bounds are causing more
problems than they are solving. However, I want to suggest that
perhaps the more fundamental issue is that Cabal asks the wrong person
to answer questions about API stability. 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

Currently *all* of these categories have the potential to break
builds, so require the big hammer of changing the first-dot version
number. I feel like I should be able to convey this level of risk,
though... and it should be able to be used by Cabal. So, here's a
proposal just to toss out there; no idea if it would be worth the
complexity or not:

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.

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.

--
Chris

Twan van Laarhoven

не прочитано,
16 серп. 2012 р., 08:42:1516.08.12
Кому: haskel...@haskell.org
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

Chris Smith

не прочитано,
16 серп. 2012 р., 09:01:4716.08.12
Кому: Twan van Laarhoven, haskel...@haskell.org
Twan van Laarhoven <twa...@gmail.com> wrote:
> 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.

Yes, it's generally low-risk, but there is *some* risk. Of course, it
could be high risk if you duplicate a Prelude function or a name that
you know is in use elsewhere in a related or core library... these
decisions would involve knowing something about the library space,
which package maintainers often do.

> I think the only meaningful distinction you can make are:

Except that the whole point is that this is *not* the only distinction
you can make. It might be the only distinction with an exact
definition that can be checked by automated tools, but that doesn't
change the fact that when I make an incompatible change to a library
I'm maintaining, I generally have a pretty good idea of which kinds of
users are going to be fixing their code as a result. The very essence
of my suggestion was that we accept the fact that we are working in
probabilities here, and empower package maintainers to share their
informed evaluation. Right now, there's no way to provide that
information: the PVP is caught up in exactly this kind of legalism
that only cares whether a break is possible or impossible, without
regard to how probable it is. The complaint that this new mechanism
doesn't have exactly such a black and white set of criteria associated
with it is missing the point.

--
Chris

Ivan Lazar Miljenovic

не прочитано,
16 серп. 2012 р., 09:20:0516.08.12
Кому: Ketil Malde, haskel...@haskell.org
On 16 August 2012 20:50, Ketil Malde <ke...@malde.org> wrote:
> "Bryan O'Sullivan" <b...@serpentine.com> writes:
>
>> I propose that the sense of the recommendation around upper bounds in the
>> PVP be reversed: upper bounds should be specified *only when there is a
>> known problem with a new version* of a depended-upon package.
>
> Another advantage to this is that it's not always clear what constitutes
> an API change. I had to put an upper bound on binary, since 0.5
> introduced laziness changes that broke my program. (I later got some
> help to implement a workaround, but binary-0.4.4 is still substantially
> faster). Understandably, the authors didn't see this as a breaking API
> change.

Except 0.4 -> 0.5 _is_ a major version bump according to the PVP.

>
> So, +1.
>
> -k
> --
> If I haven't seen further, it is by standing in the footprints of giants
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskel...@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe



timoth...@seznam.cz

не прочитано,
16 серп. 2012 р., 09:48:0716.08.12
Кому: haskel...@haskell.org

So that we are using concrete examples.  here is an example of a change that really shouldn't break any package:


https://github.com/timthelion/threadmanager/commit/c23e19cbe78cc6964f23fdb90b7029c5ae54dd35


The exposed functions are the same.  The behavior is changed.  But as the commiter of the change, I cannot imagine that it would break any currently working code.


There is another issue though.  With this kind of change, there is no reason for a package which was written for the old version of the library, to be built with the new version.  If I am correct, that this change changes nothing for currently working code, then why should an old package be built with the newer package?

The advantage in this case, is merely that we want to prevent version duplication.  We don't want to waste disk space by installing every possible iteration of a library.


I personally think that disk space is so cheep, that this last consideration is not so important.  If there are packages that only build with old versions of GHC, and old libraries, why can we not just seamlessly install them?  One problem, is if we want to use those old libraries with new code.  Take the example of Python2 vs Python3.  Yes, we can seamlessly install python2 libraries, even though we use python3 normally, but we cannot MIX python2 libraries with python3 libraries.


Maybe we could make Haskell linkable objects smart enough that we COULD mix old with new?  That sounds complicated.


I think, Michael Sloan is onto something though with his idea of compatibility layers.  I think that if we could write simple "dictionary" packages that would translate old API calls to new ones, we could use old code without modification.  This would allow us to build old libraries which normally wouldn't be compatible with something in base using a base-old-to-new dictionary package.  Then we could use these old libraries without modification with new code.


It's important that this be possible from the side of the person USING the library, and not the library author.   It's impossible to write software, if you spend all of your time waiting for someone else to update their libraries.


Timothy


---------- Původní zpráva ----------
Od: Ivan Lazar Miljenovic <ivan.mi...@gmail.com>
Datum: 16. 8. 2012
Předmět: Re: [Haskell-cafe] Platform Versioning Policy: upper bounds are not our friends

Felipe Almeida Lessa

не прочитано,
16 серп. 2012 р., 09:53:1316.08.12
Кому: Chris Smith, haskel...@haskell.org
On Thu, Aug 16, 2012 at 10:01 AM, Chris Smith <cds...@gmail.com> wrote:
> Twan van Laarhoven <twa...@gmail.com> wrote:
>> 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.
>
> Yes, it's generally low-risk, but there is *some* risk. Of course, it
> could be high risk if you duplicate a Prelude function or a name that
> you know is in use elsewhere in a related or core library... these
> decisions would involve knowing something about the library space,
> which package maintainers often do.

If you import qualified then adding functions will never break anything.

Cheers,

--
Felipe.

dag.od...@gmail.com

не прочитано,
16 серп. 2012 р., 10:30:3116.08.12
Кому: Bryan O'Sullivan, haskel...@haskell.org
On Wed, Aug 15, 2012 at 9:38 PM, Bryan O'Sullivan <b...@serpentine.com> wrote:
A benign change will obviously have no visible effect, while a compilation failure is actually better than a depsolver failure, because it's more informative.

But with upper bounds you give Cabal a chance to try and install a supported version, thus avoiding failure all together.

Yitzchak Gale

не прочитано,
16 серп. 2012 р., 10:30:0716.08.12
Кому: Haskell Cafe mailing list, Joachim Breitner
Bryan O'Sullivan wrote:
> A substantial number of the difficulties I am encountering are related to
> packages specifying upper bounds on their dependencies. This is a recurrent
> problem, and its source lies in the recommendations of the PVP itself

I think the PVP recommendation is good, though admittedly
one that in practice can be taken with a grain of salt.

Publishing supposedly stable and supported packages
with no upper bounds leads to persistent build problems
that are tricky to solve.

A good recent example is the encoding package.
This package depends on HaXML >= 1.19, with
no upper bound. However, the current version of HaXML
is 1.23, and the encoding package cannot build
against it due to API changes. Furthermore, uploading
a corrected version of encoding wouldn't even
solve the problem completely. Anyone who already
has the current version of encoding will have
build problems as soon as they upgrade HaXML.
The cabal dependencies are lying, so there is no
way for cabal to know that encoding is the culprit.
Build problems caused by missing upper bounds
last forever; their importance fades only gradually.

Whereas it is trivially easy to correct an upper
bound that has become obsolete, and once you
fix it, it's fixed.

For actively maintained packages, I think the
problem is that package maintainers don't find
out promptly that an upper bound needs to be
bumped. One way to solve that would be a
simple bot that notifies the package maintainer
as soon as an upper bound becomes out-of-date.

For unresponsive package maintainers or
unmaintained packages, it would be helpful to
have some easy temporary fix mechanism as
suggested by Joachim.

Joachim also pointed out the utility of upper bounds
for platform packaging.

Why throw away much of the robustness of
the package versioning system just because
of a problem we are having with these trivially
easy upper-bound bumps? Let's just find a
solution for the problem at hand.

Thanks,
Yitz

Brent Yorgey

не прочитано,
16 серп. 2012 р., 11:11:1616.08.12
Кому: haskel...@haskell.org
On Thu, Aug 16, 2012 at 05:30:07PM +0300, Yitzchak Gale wrote:
>
> For actively maintained packages, I think the
> problem is that package maintainers don't find
> out promptly that an upper bound needs to be
> bumped. One way to solve that would be a
> simple bot that notifies the package maintainer
> as soon as an upper bound becomes out-of-date.

This already exists:

http://packdeps.haskellers.com/

-Brent

Joey Adams

не прочитано,
16 серп. 2012 р., 18:07:0616.08.12
Кому: Bryan O'Sullivan, haskel...@haskell.org
On Wed, Aug 15, 2012 at 3:38 PM, Bryan O'Sullivan <b...@serpentine.com> wrote:
> I propose that the sense of the recommendation around upper bounds in the
> PVP be reversed: upper bounds should be specified only when there is a known
> problem with a new version of a depended-upon package.

I, too, agree. Here is my assortment of thoughts on the matter.

Here's some bad news: with cabal 1.14 (released with Haskell Platform
2012.2), cabal init defaults to bounds like these:

build-depends: base ==4.5.*, bytestring ==0.9.*, http-types ==0.6.*

Also, one problem with upper bounds is that they often backfire. If
version 0.2 of your package does not have upper bounds, but 0.2.1 does
(because you found out about a breaking upstream change), users who
try to install your package may get 0.2 instead of the latest, and
still get the problem you were trying to shield against.

A neat feature would be a cabal option to ignore upper bounds. With
--ignore-upper-bounds, cabal would select the latest version of
everything, and print a list of packages with violated upper bounds.

-Joey

wren ng thornton

не прочитано,
16 серп. 2012 р., 23:33:1716.08.12
Кому: Haskell Cafe
On 8/15/12 11:02 PM, MightyByte wrote:
> One tool-based way to help with this problem would
> be to add a flag to Cabal/cabal-install that would cause it to ignore
> upper bounds.

I'd much rather have a distinction between hard upper bounds ("known to
fail with") vs soft upper bounds ("tested with").

Soft upper bounds are good for future proofing, both short- and
long-range. So ignoring soft upper bounds is all well and good if things
still work.

However, there are certainly cases where we have hard upper
bounds[1][2][3], and ignoring those is not fine. Circumventing hard
upper bounds should require altering the .cabal file, given as getting
things to compile will require altering the source code as well. Also,
hard upper bounds are good for identifying when there are
semantics-altering changes not expressed in the type signatures of an
API. Even if relaxing the hard upper bound could allow the code to
compile, it is not guaranteed to be correct.

The problem with the current policy is that it mandates hard upper
bounds as a solution to the problem of libraries not specifying soft
upper bounds. This is indeed a tooling problem, but let's identify the
problem for what it is: not all upper bounds are created equally, and
pretending they are only leads to confusion and pain.


[1] Parsec 2 vs 3, for a very long time
[2] mtl 1 vs 2, for a brief interim
[3] John Lato's iteratee <=0.3 vs >=0.4, for legacy code
...

--
Live well,
~wren

Daniel Trstenjak

не прочитано,
17 серп. 2012 р., 04:13:0017.08.12
Кому: wren ng thornton, Haskell Cafe

On Thu, Aug 16, 2012 at 11:33:17PM -0400, wren ng thornton wrote:
> However, there are certainly cases where we have hard upper
> bounds[1][2][3], and ignoring those is not fine. Circumventing hard
> upper bounds should require altering the .cabal file, given as
> getting things to compile will require altering the source code as
> well.

It's ok to have soft and hard upper bounds, but it should be always
possible to ignore both - having a separate ignore option for each -
without modifying the cabal file.

I've the confidence, that most cabal users should be able to handle
this. Nothing is more annoying if you know what you're doing, but don't
have the power to do it.


Greetings,
Daniel

Heinrich Apfelmus

не прочитано,
17 серп. 2012 р., 07:48:2517.08.12
Кому: haskel...@haskell.org
Brent Yorgey wrote:
> Yitzchak Gale wrote:
>> For actively maintained packages, I think the
>> problem is that package maintainers don't find
>> out promptly that an upper bound needs to be
>> bumped. One way to solve that would be a
>> simple bot that notifies the package maintainer
>> as soon as an upper bound becomes out-of-date.
>
> This already exists:
>
> http://packdeps.haskellers.com/

Indeed. It even has RSS feeds, like this

http://packdeps.haskellers.com/feed/reactive-banana

Extremely useful!


Best regards,
Heinrich Apfelmus

--
http://apfelmus.nfshost.com

Thomas Schilling

не прочитано,
17 серп. 2012 р., 11:25:4517.08.12
Кому: Haskell Café List
My thoughts on the matter got a little long, so I posted them here:

--
Push the envelope. Watch it bend.

Leon Smith

не прочитано,
17 серп. 2012 р., 11:28:2917.08.12
Кому: Joachim Breitner, haskel...@haskell.org
I see good arguments on both sides of the upper bounds debate,  though at the current time I think the best solution is to omit upper bounds (and I have done so for most/all of my packages on hackage).    But I cannot agree with this enough:


On Thu, Aug 16, 2012 at 4:45 AM, Joachim Breitner <ma...@joachim-breitner.de> wrote:
I think what we’d need is a more relaxed policy with modifying a
package’s meta data on hackage. What if hackage would allow uploading a
new package with the same version number, as long as it is identical up
to an extended version range? Then the first person who stumbles over an
upper bound that turned out to be too tight can just fix it and upload
the fixed package directly, without waiting for the author to react.

I think that constraint ranges of a given package should be able to both be extended and restricted after the fact.   Those in favor of the reactionary approach (as I am at the moment, or Bryan O'Sullivan) would find the ability of to restrict the version range useful,  while those in favor of the proactive approach (like Joachim Breitner or Doug Beardsley) would find the ability to extend the version range useful.

I suspect that attitudes towards upper bounds may well change if we can set version ranges after the fact.    I know mine very well might.    And the difference between reactionary and proactive approaches I think is a potential justification for the "hard" and "soft" upper bounds;  perhaps we should instead call them "reactionary" and "proactive" upper bounds instead.

MigMit

не прочитано,
17 серп. 2012 р., 15:34:3217.08.12
Кому: Leon Smith, Joachim Breitner, haskel...@haskell.org
What if instead of upper (and lower) bounds we just specify our interface requirements? Like "package bull-shit should provide value Foo.Bar.baz :: forall a. [a] -> [a] -> [a] or more general". Sure, it won't help dealing with strictness/lazyness, but it would capture most interface differences. And, in case the requirements aren't specified, we could also specify the default, like "bool-shit 2.0 is known to fulfil this requirement; if yours doesn't, consider installing this one".
> I suspect that attitudes towards upper bounds may well change if we can set version ranges after the fact. I know mine very well might. And the difference between reactionary and proactive approaches I think is a potential justification for the "hard" and "soft" upper bounds; perhaps we should instead call them "reactionary" and "proactive" upper bounds instead. _______________________________________________

Bryan O'Sullivan

не прочитано,
17 серп. 2012 р., 16:35:2017.08.12
Кому: MigMit, Joachim Breitner, haskel...@haskell.org
On Fri, Aug 17, 2012 at 12:34 PM, MigMit <migue...@yandex.ru> wrote:
What if instead of upper (and lower) bounds we just specify our interface requirements?

We already have a simple versioning scheme for which, despite it being easy to grasp, we have amply demonstrated that we cannot make it work well, because it has emergent properties that cause it to not scale well across a large community.

Any vastly more complicated and detailed versioning scheme has a huge burden to prove that it won't collapse dramatically more quickly. (Frankly, I think that anything involving "specify every detail of your known dependencies" is dead on arrival from a practical standpoint: it's way too much work.)

For that matter, I think that this burden applies to my own proposal to omit upper bounds unless they're needed.

Fortunately, we now have several years of historical dependency data that we can go back and mine, and thereby try to model the effects of particular suggested changes.

MigMit

не прочитано,
17 серп. 2012 р., 16:47:3617.08.12
Кому: Bryan O'Sullivan, Joachim Breitner, haskel...@haskell.org

On Aug 18, 2012, at 12:35 AM, "Bryan O'Sullivan" <b...@serpentine.com> wrote:

> We already have a simple versioning scheme for which, despite it being easy to grasp, we have amply demonstrated that we cannot make it work well, because it has emergent properties that cause it to not scale well across a large community.

Well, I think that the main reason for this failure is that despite being easy to grasp, this scheme doesn't really reflect the reality. It seems to be chosen arbitrarily.

> Any vastly more complicated and detailed versioning scheme has a huge burden to prove that it won't collapse dramatically more quickly. (Frankly, I think that anything involving "specify every detail of your known dependencies" is dead on arrival from a practical standpoint: it's way too much work.)

That's not true. All this work can be automated — if you're the developer, you've certainly compiled the code yourself, and the compiler knows what was imported from other packages. The only problem is to make it save this information into a specific file.

Brandon Allbery

не прочитано,
17 серп. 2012 р., 17:34:1617.08.12
Кому: Bryan O'Sullivan, Joachim Breitner, haskel...@haskell.org, MigMit
On Fri, Aug 17, 2012 at 4:35 PM, Bryan O'Sullivan <b...@serpentine.com> wrote:
Any vastly more complicated and detailed versioning scheme has a huge burden to prove that it won't collapse dramatically more quickly. (Frankly, I think that anything involving "specify every detail of your known dependencies" is dead on arrival from a practical standpoint: it's way too much work.)

If you do it in terms of hashed signatures, you can make the compiler and toolchain do the work for you.  The problem with version numbers is that it *is* manual.  It can't catch behavioral changes, though; you probably need some kind of epoch override for that in the case where it doesn't come with corresponding API changes.

The reason it's never done is that you can't really do it with C or C++.  We can mostly avoid that (the FFI is an issue, but it is anyway:  cabal can't really check C stuff, unless you use pkg-config which was two operating modes:  exact versions or no versioning).

Michael Sloan

не прочитано,
17 серп. 2012 р., 17:54:5717.08.12
Кому: Brandon Allbery, Joachim Breitner, MigMit, haskel...@haskell.org
I agree that Haskell's design gives us a good leg up on the problem of
acquiring and comparing APIs. However, I don't think that this
manifest solution really buys us enough to justify the complexity.

There're also some specific, perhaps resolvable, but unsightly problems, which
I outline here:
http://www.reddit.com/r/haskell/comments/ydtl9/beyond_package_version_policies/c5uro04

(also another pitch for my proposed solution to this variety of problems)

-mgsloan

Gershom Bazerman

не прочитано,
17 серп. 2012 р., 18:19:1617.08.12
Кому: haskel...@haskell.org
On 8/16/12 11:33 PM, wren ng thornton wrote:
> [1] Parsec 2 vs 3, for a very long time
> [2] mtl 1 vs 2, for a brief interim
> [3] John Lato's iteratee <=0.3 vs >=0.4, for legacy code
> ...

I think this is a great point! As others have said, maintainers
typically, but not always, know when their code is likely to break
client libraries and software. But super-major numbers (i.e. the x of
x.y) get bumped for other reasons, and sometimes sub-major (majorette?)
numbers (i.e. the y of x.y) get bumped for massively breaking changes as
well (which is in perfect accord with the PVP).

One other solution would be to introduce a new, optional (at least at
first) field in cabal files -- perhaps named something like
"api-version" or "api-epoch". This is just an integer, and it just gets
bumped on massively breaking changes likely to force all client code to
adapt. That way I can specify a traditional package lower bound with a
real version number, and also specify (optionally, at least at first) an
"upper bound" of an api-epoch. Most of my packages have never
experienced an api-epoch event, and many likely won't ever. Most of
their dependencies -- likewise.

At the cost of some extra (optional) annotations, this gives us a sort
of compromise between the current, very painful, situation and the
no-upper-bound situation where occasionally an epoch event breaks an
enormous chunk of the ecosystem.

Cheers,
Gershom

David Feuer

не прочитано,
18 серп. 2012 р., 02:57:3218.08.12
Кому: Felipe Almeida Lessa, haskel...@haskell.org
On Thu, Aug 16, 2012 at 9:53 AM, Felipe Almeida Lessa
<felipe...@gmail.com> wrote:

> If you import qualified then adding functions will never break anything.

If the language is changed (without possibility of breakage, I
believe) so that names declared in a module shadow imported names,
incompatibility can only arise if two different imports offer the same
name, and it is actually used.

David

wren ng thornton

не прочитано,
18 серп. 2012 р., 23:52:0918.08.12
Кому: haskel...@haskell.org
On 8/17/12 11:28 AM, Leon Smith wrote:
> And the
> difference between reactionary and proactive approaches I think is a
> potential justification for the "hard" and "soft" upper bounds; perhaps we
> should instead call them "reactionary" and "proactive" upper bounds instead.

I disagree. A hard constraint says "this package *will* break if you
violate me". A soft constraint says "this package *may* break if you
violate me". These are vastly different notions of boundary conditions,
and they have nothing to do with a proactive vs reactionary stance
towards specifying constraints (of either type).

The current problems of always giving (hard) upper bounds, and the
previous problems of never giving (soft) upper bounds--- both stem from
a failure to distinguish hard from soft! The current/proactive approach
fails because the given constraints are interpreted by Cabal as hard
constraints, when in truth they are almost always soft constraints. The
previous/reactionary approach fails because when the future breaks noone
bothered to write down when the last time things were known to work.

To evade both problems, one must distinguish these vastly different
notions of boundary conditions. Hard constraints are necessary for
blacklisting known-bad versions; soft constraints are necessary for
whitelisting known-good versions. Having a constraint at all shows where
the grey areas are, but it fails to indicate whether that grey is most
likely to be black or white.

--
Live well,
~wren

Felipe Almeida Lessa

не прочитано,
19 серп. 2012 р., 08:39:3019.08.12
Кому: David Feuer, haskel...@haskell.org
On Sat, Aug 18, 2012 at 3:57 AM, David Feuer <david...@gmail.com> wrote:
> If the language is changed (without possibility of breakage, I
> believe) so that names declared in a module shadow imported names,
> incompatibility can only arise if two different imports offer the same
> name, and it is actually used.

This already happens in practice (e.g. "take", how many modules
declare that?) and is one of the problems that qualified imports
solve.

Cheers,

--
Felipe.

Chris Dornan

не прочитано,
19 серп. 2012 р., 17:22:1719.08.12
Кому: MightyByte, Ivan Lazar Miljenovic, Bryan O'Sullivan, Haskell Cafe
I agree with Bryan's proposal unreservedly.

However, I think there might be a way to resolve the tension between:

* maintaining and publishing a definite dependent-package configuration
that is known to work and

* having a package unencumbered with arbitrary restrictions on which
future versions of its dependent packages it will work with.

Can't we have both? The cabal file would only eliminate package version that
are known not to work as Bryan suggests but the versions of the dependent
packages that the package has been tested with -- the 'reference
configuration' -- could be recorded separately. A separate build tool could
take the reference configuration and direct cabal to rebuild the reference
instance, specifying the fully qualified packages to use.

I have a set of tools for doing this because (see http://justhub.org -- and
if you have root access to an RPM-based Linux then the chances are you can
try it out, otherwise the sources are available).

For each project or package, separate from the cabal file recording the hard
dependencies, I record the current reference configuration in a file which
lists the base installation (generally a Haskell platform but it can be a
bare compiler) and the list of fully-qualified dependent modules. Like the
cabal file the reference configuration would get checked into the VCS and/or
included in the Hackage tarball.

A normal build process first builds the environment ensuring that the
correct platform is selected and the exact package dependencies are
installed -- this is usually just a checking step unless the package
environment has been disturbed or the reference configuration has been
revised. Once the environment has been checked the normal program build
process proceeds as normal, where the real work generally happens.

Once the project is checked out on another system (or a package is installed
anew) the build step would actually build all of the dependent packages.

For this to really work a sandbox mechanism is needed -- merely trying out a
package/project shouldn't trash your only development environment!

If a library package is to be integrated into a live project the reference
environment probably won't be the one you need but I find it useful to be
able to build it anyway in a clean environment and incrementally
up/downgrade the packages, searching out a compatible configuration. (Being
able to easily push and recover sandboxes is helpful here too.)

Would this way of working resolve the tension we are seeing here? I am so
used to working this way it is difficult for me to say.

(As others have said here and elsewhere, functional packaging is really
cool.)

Chris


-----Original Message-----
From: haskell-ca...@haskell.org
[mailto:haskell-ca...@haskell.org] On Behalf Of MightyByte
Sent: 16 August 2012 04:02
To: Ivan Lazar Miljenovic
Cc: Haskell Cafe
Subject: Re: [Haskell-cafe] Platform Versioning Policy: upper bounds are not
our friends

On Wed, Aug 15, 2012 at 9:19 PM, Ivan Lazar Miljenovic
<ivan.mi...@gmail.com> wrote:
> On 16 August 2012 08:55, Brandon Allbery <allb...@gmail.com> wrote:
>> Indeed. But the ghc release that split up base broke cabalised
>> packages with no warning to users until they failed to compile.
>> Upper bounds were put in place to avoid that kind of breakage in the
future.
>
> I like having upper bounds on version numbers... right up until people
> abuse them.

I also tend to favor having upper bounds. Obviously they impose a cost, but
it's not clear to me at all that getting rid of them is a better tradeoff.
I've had projects that I put aside for awhile only to come back and discover
that they would no longer build because I hadn't put upper bounds on all my
package dependencies. With no upper bounds, a package might not be very
likely to break for incremental version bumps, but eventually it *will*
break. And when it does it's a huge pain to get it building again. If I
have put effort into making a specific version of my package work properly
today, I want it to always work properly in the future (assuming that
everyone obeys the PVP). I don't think it's unreasonable that some
activation energy be required to allow one's project to work with a new
version of some upstream dependency.

Is that activation energy too high right now? Almost definitely. But
that's a tool problem, not a problem with the existence of upper bounds
themselves. One tool-based way to help with this problem would be to add a
flag to Cabal/cabal-install that would cause it to ignore upper bounds.
(Frankly, I think it would also be great if Cabal/cabal-install enforced
upper version bounds automatically if none were specified.) Another
approach that has been discussed is detecting dependencies that are only
used internally[1], and I'm sure there are many other possibilities. In
short, I think we should be moving more towards purely functional builds
that reduce the chance that external factors will break things, and it seems
like removing upper version bounds is a step in the other direction.

[1]
http://cdsmith.wordpress.com/2011/01/21/a-recap-about-cabal-and-haskell-libr
aries/

Erik Hesselink

не прочитано,
20 серп. 2012 р., 03:33:2220.08.12
Кому: Bryan O'Sullivan, haskel...@haskell.org
I am strongly against this, especially for packages in the platform.

If you fail to specify an upper bound, and I depend on your package,
your dependencies can break my package! For example, say I develop
executable A and I depend on library B == 1.0. Library B depends on
library C >= 0.5 (no upper bound). Now C 0.6 is released, which is
incompatible with B. This suddenly breaks my build, even though I have
not changed anything about my code or dependencies. This goes against
the 'robust' aspect mentioned as one of the properties of the Haskell
platform, and against the Haskell philosophy of correctness in
general.

This is not an imaginary problem. At my company, we've run into these
problems numerous times already. Since we also have people who are not
experts at Cabal and the Haskell ecosystem building our software, this
can be very annoying. The fix is also not trivial: we can add a
dependency on a package we don't use to all our executables or we can
fork the library (B, in the example above) and add an upper bound/fix
the code. Both add a lot of complexity that we don't want. Add to that
the build failures and associated emails from CI systems like Jenkins.

I can see the maintenance burder you have, since we have to do the
same for our code. But until some Cabal feature is added to ignore
upper bounds or specify soft upper bounds, please follow the PVP, also
in this regard. It helps us maintain a situation where only our own
actions can break our software.

Erik

On Wed, Aug 15, 2012 at 9:38 PM, Bryan O'Sullivan <b...@serpentine.com> wrote:
> Hi, folks -
>
> I'm sure we are all familiar with the phrase "cabal dependency hell" at this
> point, as the number of projects on Hackage that are intended to hack around
> the problem slowly grows.
>
> I am currently undergoing a fresh visit to that unhappy realm, as I try to
> rebuild some of my packages to see if they work with the GHC 7.6 release
> candidate.
>
> A substantial number of the difficulties I am encountering are related to
> packages specifying upper bounds on their dependencies. This is a recurrent
> problem, and its source lies in the recommendations of the PVP itself
> (problematic phrase highlighted in bold):
>
>> When publishing a Cabal package, you should ensure that your dependencies
>> in the build-depends field are accurate. This means specifying not only
>> lower bounds, but also upper bounds on every dependency.
>
>
> I understand that the intention behind requiring tight upper bounds was
> good, but in practice this has worked out terribly, leading to depsolver
> failures that prevent a package from being installed, when everything goes
> smoothly with the upper bounds relaxed. The default response has been for a
> flurry of small updates to packages in which the upper bounds are loosened,
> thus guaranteeing that the problem will recur in a year or less. This is
> neither sensible, fun, nor sustainable.
>
> In practice, when an author bumps a version of a depended-upon package, the
> changes are almost always either benign, or will lead to compilation failure
> in the depending-upon package. A benign change will obviously have no
> visible effect, while a compilation failure is actually better than a
> depsolver failure, because it's more informative.
>
> This leaves the nasty-but-in-my-experience-rare case of runtime failures
> caused by semantic changes. In these instances, a downstream package should
> reactively add an upper bound once a problem is discovered.
>
> I propose that the sense of the recommendation around upper bounds in the
> PVP be reversed: upper bounds should be specified only when there is a known
> problem with a new version of a depended-upon package.

Chris Dornan

не прочитано,
20 серп. 2012 р., 09:13:5720.08.12
Кому: Erik Hesselink, Bryan O'Sullivan, haskel...@haskell.org
I think we should encourage stable build environments to know precisely
which package versions they have been using and to keep using them until
told otherwise. Even when the types and constraints all work out there is a
risk that upgraded packages will break. Everybody here wants cabal to just
install the packages without problem, but if you want to insulate yourself
from package upgrades surely sticking with proven combinations is the way to
go.

Chris

-----Original Message-----
From: haskell-ca...@haskell.org
[mailto:haskell-ca...@haskell.org] On Behalf Of Erik Hesselink
Sent: 20 August 2012 08:33
To: Bryan O'Sullivan
Cc: haskel...@haskell.org
Subject: Re: [Haskell-cafe] Platform Versioning Policy: upper bounds are not
our friends

Simon Marlow

не прочитано,
20 серп. 2012 р., 09:24:5620.08.12
Кому: Johan Tibell, Duncan Coutts, haskel...@haskell.org
On 15/08/2012 21:44, Johan Tibell wrote:
> On Wed, Aug 15, 2012 at 1:02 PM, Brandon Allbery <allb...@gmail.com> wrote:
>> So we are certain that the rounds of failures that led to their being
>> *added* will never happen again?
>
> It would be useful to have some examples of these. I'm not sure we had
> any when we wrote the policy (but Duncan would know more), but rather
> reasoned our way to the current policy by saying that things can
> theoretically break if we don't have upper bounds, therefore we need
> them.

I haven't read the whole thread (yet), but the main motivating example
for upper bounds was when we split the base package (GHC 6.8) -
virtually every package on Hackage broke. Now at the time having upper
bounds wouldn't have helped, because you would have got a depsolver
failure instead of a type error. But following the uproar about this we
did two things: the next release of GHC (6.10) came with two versions of
base, *and* we recommended that people add upper bounds. As a result,
packages with upper bounds survived the changes.

Now, you could argue that we're unlikely to do this again. But the main
reason we aren't likely to do this again is because it was so painful,
even with upper bounds and compatibility libraries. With better
infrastructure and tools, *and* good dependency information, it should
be possible to do significant reorganisations of the core packages.

As I said in my comments on Reddit[1], I'm not sure that removing upper
bounds will help overall. It removes one kind of failure, but
introduces a new kind - and the new kind is scary, because existing
working packages can suddenly become broken as a result of a change to a
different package. Will it be worse or better overall? I have no idea.
What I'd rather see instead though is some work put into
infrastructure on Hackage to make it easy to change the depdendencies on
existing packages.

Cheers,
Simon

[1]
http://www.reddit.com/r/haskell/comments/ydkcq/pvp_upper_bounds_are_not_our_friends/c5uqohi

Erik Hesselink

не прочитано,
20 серп. 2012 р., 09:34:4920.08.12
Кому: Chris Dornan, haskel...@haskell.org
Hub looks interesting, I'll have to try it out (though I'm not on an
RPM based distro). But isn't this the goal of things like semantic
versioning [0] and the PVP? To know that you can safely upgrade to a
bugfix release, and relavily safely to a minor release, but on a major
release, you have to take care?

Haskell makes it much easier to see if you can use a new major (or
minor) version of a library, since the type checker catches many (but
not all!) problems for you. However, this leads to libraries breaking
their API's much more easily, and that in turn causes the problems
voiced in this thread. However, fixing all versions seems like a bit
of a blunt instrument, as it means I'll have to do a lot of work to
bring even bug fixes in.

Erik

[0] http://semver.org/

Chris Dornan

не прочитано,
20 серп. 2012 р., 10:03:2120.08.12
Кому: Erik Hesselink, haskel...@haskell.org
Of course if you wish or need to upgrade a package then you can just upgrade
it -- I am not suggesting anyone should forgo upgrades! It is just that
there is no need to make the stability of a build process dependent on new
package releases.

To upgrade a package I would fork my sandbox, hack away at the package
database (removing, upgrading, installing packages) until I have a candidate
combination of packages and swap in the new sandbox into my work tree and
test it, reverting to the tried and tested environment if things don't work
out. If the new configuration works then then I would dump the new package
configuration and check it in. Subsequent updates and builds on other work
trees should pick up the new environment.

The key thing I was looking for was control of when your build environment
gets disrupted and stability in between -- even when building from the repo.

Chris

Gregory Collins

не прочитано,
20 серп. 2012 р., 10:03:5820.08.12
Кому: Bryan O'Sullivan, haskel...@haskell.org
My two (or three) cents:
  • Given a choice between a world where there is tedious work for package maintainers vs. a world where packages randomly break for end users (giving them a bad impression of the entire Haskell ecosystem), I choose the former.

  • More automation can ease the burden here. Michael Snoyman's packdeps tool is a great start in this direction, and it would be even better if it automagically fixed libraries for you and bumped your version number according to the PVP.

  • This is a great problem to have. There's so much work happening that people find it hard to stay on the treadmill? Things could be a lot worse. I guarantee you that our friends in the Standard ML community are not having this discussion. :-)
G
--
Gregory Collins <gr...@gregorycollins.net>

Brent Yorgey

не прочитано,
20 серп. 2012 р., 10:11:3320.08.12
Кому: haskel...@haskell.org
On Thu, Aug 16, 2012 at 06:07:06PM -0400, Joey Adams wrote:
> On Wed, Aug 15, 2012 at 3:38 PM, Bryan O'Sullivan <b...@serpentine.com> wrote:
> > I propose that the sense of the recommendation around upper bounds in the
> > PVP be reversed: upper bounds should be specified only when there is a known
> > problem with a new version of a depended-upon package.
>
> I, too, agree. Here is my assortment of thoughts on the matter.
>
> Here's some bad news: with cabal 1.14 (released with Haskell Platform
> 2012.2), cabal init defaults to bounds like these:
>
> build-depends: base ==4.5.*, bytestring ==0.9.*,
> http-types ==0.6.*

I'm not sure why you think this is "bad news". I designed this to
conform exactly to the current PVP. If the PVP is changed then I will
update cabal init to match.

-Brent

Iavor Diatchki

не прочитано,
20 серп. 2012 р., 19:58:0120.08.12
Кому: haskel...@haskell.org
Hello,

I also completely agree with Bryan's point which is why I usually don't add upper bounds on the dependencies of the packages that I maintain---I find that the large majority of updates to libraries tend to be backward compatible, so being optimistic seems like a good idea.

By the way, something I encounter quite often is a situation where two packages both build on Hacakge just fine, but are not compatible with each other.  Usually it goes like this:

  1. Package A requires library X >= V  (typically, because it needs a bug fix or a new feature).
  2. Package B requires library X < V (typically, because someone added a conservative upper bound that needs to be updated).

Trying to use A and B together leads to failure, which is usually resolved by having to install B manually, and remove it's upper bound by hand.  This is rather unfortunate, because not only it's inconvenient but, also, now there is no released version of package B that you can explicitly depend on.

-Iavor

Leon Smith

не прочитано,
22 серп. 2012 р., 09:18:2122.08.12
Кому: wren ng thornton, haskel...@haskell.org
I think we actually agree more than we disagree;  I do think distinguishing hard and soft upper bounds (no matter what they are called)  would help,  and I'm just trying to justify them to some of the more dismissive attitudes towards the idea 

The only thing I think we (might) disagree on is the relative importance of distinguishing hard and soft bounds versus being able to change bounds easily after the fact (and *without* changing the version number associated with the package.)   

And on that count,  given the choice,  I pick being able to change bounds after the fact, hands down.   I believe this is more likely to significantly improve the current situation than distinguishing the two types of bound alone.   However,  being able to specify both (and change both) after the fact may prove to be even better.

Best,
Leon

David Menendez

не прочитано,
22 серп. 2012 р., 12:35:2622.08.12
Кому: Leon Smith, haskel...@haskell.org
As I see it, there are four possibilities for a given version of dependency:

1. The version DOES work. The author (or some delegate) has compiled
the package against this version and the resulting code is considered
good.
2. The version SHOULD work. No one has tested against this version,
but the versioning policy promises not to break anything.
3. The version MIGHT NOT work. No one has tested against this version,
and the versioning policy allows breaking changes.
4. The version DOES NOT work. This has been tested and the resulting
code (if any) is considered not good.

Obviously, cases 1 and 4 can only apply to previously released
versions. The PVP requires setting upper bounds in order to
distinguish cases 2 and 3 for the sake of future compatibility.
Leaving off upper bounds except when incompatibility is known
essentially combines cases 2 and 3.

So there are two failure modes:

I. A version which DOES work is outside the bounds (that is, in case
3). I think eliminating case 3 is too extreme. I like the idea of
temporarily overriding upper bounds with a command-line option. The
danger here is that we might actually be in case 4, in which case we
don't want to override the bounds, but requiring an explicit override
gives users a chance to determine if a particular version is
disallowed because it is untested or because it is known to be
incompatible.

II. A version which DOES NOT work is inside the bounds (that is, in
case 2). This happens when a package does not follow its own version
policy. For example, during the base-4 transition, a version of
base-3.0 was released which introduced a few breaking changes (e.g.,
it split the Arrow class). Alternately, a particular version might be
buggy. This can already be handled by adding constraints on the
command line, but it's better to release a new version of the package
with more restrictive constraints.

(This might not be enough, though. If I release foo-1.0.0 which
depends on bar-1.0.*, and then bar-1.0.1 is released with with a bug
or breaking change, I can release foo-1.0.0.1 which disallows
bar-1.0.1. But we need some way of preventing cabal from using
foo-1.0.0. Can Hackage deprecate specific versions?)
--
Dave Menendez <da...@zednenem.com>
<http://www.eyrie.org/~zednenem/>

wren ng thornton

не прочитано,
23 серп. 2012 р., 21:20:1023.08.12
Кому: haskel...@haskell.org
On 8/22/12 9:18 AM, Leon Smith wrote:
> I think we actually agree more than we disagree; I do think distinguishing
> hard and soft upper bounds (no matter what they are called) would help,
> and I'm just trying to justify them to some of the more dismissive
> attitudes towards the idea

Hopefully. Though you suggested conflating the hard/soft distinction and
the reactive/proactive distinction, and I can't see how that would even
make sense. The former is a matter of ontology (i.e., categorization of
what things can/do/should exist), whereas the latter is a matter of
policy (i.e., how people can/do/should behave). Clearly there's some
relation between the two, but the distinctions are talking about
completely different topics.


> The only thing I think we (might) disagree on is the relative importance of
> distinguishing hard and soft bounds versus being able to change bounds
> easily after the fact (and *without* changing the version number associated
> with the package.)
>
> And on that count, given the choice, I pick being able to change bounds
> after the fact, hands down.

Well sure, just updating Cabal to say it has soft upper bounds doesn't
mean much unless they're actually overridable somehow ;)


I'm still dubious of being able to override hard bounds with a
commandline flag. If the hard bound is valid then when you pass the flag
to ignore the bound either (a) the code won't compile ---so the flag
doesn't help any---, or (b) the code will compile in a way known to be
silently wrong/buggy ---so the flag is evil. Circumventing a (valid)
hard bound is going to require altering the code, so what benefit is
there in avoiding to alter the .cabal file at the same time?

The only case I can conceive of it being helpful to circumvent a hard
bound is if, in fact, the statement of the hard bound is incorrect. But,
if that's the case, it's a bug; and surely correcting that bug should
warrant nudging the fourth version number, ne? Also, this situation
doesn't strike me as being common enough to warrant the effort of
implementation. If it came for free from whatever work it takes to
implement soft bounds (which must necessarily be overridable), I
wouldn't really care. But if eliminating this burden would help in
getting soft bounds implemented, then I see no downside to axing it.

wren ng thornton

не прочитано,
23 серп. 2012 р., 21:50:1723.08.12
Кому: haskel...@haskell.org
On 8/22/12 12:35 PM, David Menendez wrote:
> As I see it, there are four possibilities for a given version of dependency:
>
> 1. The version DOES work. The author (or some delegate) has compiled
> the package against this version and the resulting code is considered
> good.
> 2. The version SHOULD work. No one has tested against this version,
> but the versioning policy promises not to break anything.
> 3. The version MIGHT NOT work. No one has tested against this version,
> and the versioning policy allows breaking changes.
> 4. The version DOES NOT work. This has been tested and the resulting
> code (if any) is considered not good.
>
> Obviously, cases 1 and 4 can only apply to previously released
> versions. The PVP requires setting upper bounds in order to
> distinguish cases 2 and 3 for the sake of future compatibility.
> Leaving off upper bounds except when incompatibility is known
> essentially combines cases 2 and 3.

Right-o.


> So there are two failure modes:
>
> I. A version which DOES work is outside the bounds (that is, in case
> 3). I think eliminating case 3 is too extreme. I like the idea of
> temporarily overriding upper bounds with a command-line option. The
> danger here is that we might actually be in case 4, in which case we
> don't want to override the bounds, but requiring an explicit override
> gives users a chance to determine if a particular version is
> disallowed because it is untested or because it is known to be
> incompatible.

There are two failure modes with overriding stated bounds, however. On
the one hand, the code could fail to compile. Okay, we know we're in
case 4; all is well. On the other hand the code could successfully
compile in ways the package designer knows to be buggy/wrong; we're
actually in case 4, but the user does not know this. This is why it's
problematic to simply allow overriding constraints. The package
developer has some special knowledge that the compiler lacks, but if all
constraints are considered equal then the developer has no way to convey
that knowledge to the user (i.e., in an automated machine-checkable
way). Consequently, the user can end up in a bad place because they
thought this second failure mode was actually the success mode.

This is why I advocate distinguishing hard constraints from soft
constraints. By making this distinction, the developer has a means of
conveying their knowledge to users. A soft bound defines an explicit
boundary between case 1 and cases 2--4, which can be automatically (per
PVP) extended to an implicit boundary between cases 1--2 and cases 3--4;
a boundary which, as you say, can only be truly discovered after the
code has been published. Extending soft boundaries in this way should be
safe; at least it's as safe as possible with the foresight available to
us. On the other hand, a hard bound defines an explicit boundary between
case 4 and cases 1--3. If these are overridable, things may break
silently as discussed above--- but the important thing is, in virtue of
distinguishing hard and soft bounds, the user is made aware of this
fact. By distinguishing hard and soft bounds, the developer can convey
their special knowledge to the user. The user can ignore this
information, but at least they'll do so in an informed way.

Alberto G. Corona

не прочитано,
23 вер. 2012 р., 06:51:1523.09.12
Кому: wren ng thornton, haskel...@haskell.org
Just thinking  aloud:

What if  we add  "-current"  ?

pacage -current 

Would select the versions of the package that were current art the time the cabal file was uploaded and sucessfully compiled in hackage,  if the packae is installed from hackage

If the cabal file is local then current == any.

This option would eliminate the need to guess bounds for package dependencies. It would also give more guaranties that the package will compile sucessfully when downloaded from hackage.

Certainly,it would not guarantee it if your version of ghc differs from the one in Hackage, but it would make things more simple and would reduce the spectrum of possible failures


2012/8/24 wren ng thornton <wr...@freegeek.org>



--
Alberto.
Відповісти всім
Відповісти автору
Переслати
0 нових повідомлень