Prelude: 3 Release Policy

461 views
Skip to first unread message

Edward Kmett

unread,
Oct 12, 2015, 8:42:55 PM10/12/15
to core-librari...@haskell.org
Recently there has been a bunch of chatter about ways to mitigate the amount of CPP pushed on users by changes to the Prelude.

In particular the discussion has been around the idea of trying to ensure that it is possible to write code in _some_ way without CPP that can run backwards for 3 releases of GHC, preferably in a -Wall safe manner. The approach they may have to use may not be the idiomatic way, but in general it should exist. 

Gershom ran around at the Haskell Exchange sounding folks out about this idea, and it seems to codify a reasonable tension between the "change nothing" and "change everything" camps. The feedback thus far seems to be noises of "grumbling acceptance" rather than the current state of outright panic that we might do anything at any time.

I'm personally considering this a very high priority for all changes to Prelude going forward. 

The 3 years forms a backward-facing window, not a guarantee against future change, but we should of course try to let folks know what is coming with a decent time horizon so folks can look forward as well. That is a separate concern, though.

I'm not ready to give the "3 release policy" outright veto power over new functionality, but at least if we have two plans that can in the end yield the same end state, we should definitely err on the side of the plan that falls within these guidelines, and be very well ready to explain to a rather irate community when we violate this rubric. It shouldn't be done lightly, if at all, if we can help it!

All in all it is a fairly weak guarantee, but it does have some impact on current items under consideration.

Off the top of my head:

* A number of new members for Floating were passed by proposal back before 7.10 went out the door, but haven't found their way into base yet: expm1, log1p, etc. are absolutely required for decent precision numerics. When the proposal passed we ultimately decided _not_ to include default definitions for these to force authors to implement them explicitly. Under the guidelines here, the plan would likely have to include default definitions for these to start when introducing them in 8.0. Then in 8.4 we could in theory remove the defaults and remain in compliance with the letter of the law here or introduce an ad hoc warning about lack of implementation, and remove the defaults in 8.6, depending on how gradual an introduction we wanted to give. We wouldn't be able to do the warnings in 8.2, however, and remain within the letter of the law, and we wouldn't be able to introduce them without defaults without violating the no-warnings guideline.

* MonadFail reform proposal wouldn't be able to start issuing warnings about missing instances until 8.4 even if we put in MonadFail into a module today. This would likely delay the full implementation of the proposal to 8.6 as well.

* The Semigroup as a superclass of Monoid proposal runs into a similar clock.

An immediate consequence is that creating a class in base (or moving one into base) and moving it into Prelude changes picks up a 3-4 year window for implementation. (3 years from this guideline, and a year if we want to / should give warnings about missing instances, which as mentioned above, is a separate concern.)

Observations:

This doesn't imply the lack of warnings for new names coming into Prelude, because code can be changed to use the new names in a backwards compatible way. The AMP warnings would be in compliance.

I don't think we can viably apply this reasoning to other modules in base or even most other packages under the core libraries purview: It'd be nice, but things like template-haskell change on too quick a clock. For other modules in base or other libraries in scope of the core libraries process, I'd probably consider this guideline demoted from "should" to "may".

When Data.Proxy or Data.Void were brought into base they were brought in more or less unmolested from tagged and void respectively with only minor differences. 

This means that code that wants to use them with older versions of the compiler can use their pre-existing dependency as a conditional (or mandatory) listed dependency. This means that code that was using them before continues to work fine despite their incorporation into base. Compliance with this rule also acts as a hedge against severe bikeshedding when we incorporate more stuff.

In the case of Semigroup you can use the semigroups package today in a form that is backwards compatible for a half dozen We could ship a 'fail' package that gave you access to the MonadFail class across older GHC versions. 

The question then becomes is it worth trying to use the existence of those packages to try to "cheat the clock"? I think we'd almost assuredly be rightly called out for 'cheating' by package maintainers where a fresh 'fail' package was concerned, but given the widespread distribution of 'semigroups' it might be plausible to use that to justify finishing out that proposal in 8.4 (end of 2017) rather than 8.6 (end of 2018). Personally, I'm content with the longer clock and don't think it'd be worth doing in this case, but it was an informative exercise to consider. At the least, the existence of such packages lets us go much farther back than 3 releases for folks who have a wider support window.

Again, the above guideline would basically imply that if you wanted to add a thing to base and get it into the Prelude you can't do it in less than 3 years. Given the stability of Prelude this is the _least_ we can do. Now nobody needs to worry about us rushing off to add Pointed or Semiapplicative to Prelude in the short term. It simply can't move into base and happen that fast.

Things already in base could admittedly take a shorter path and comply, but it is worth noting that this is just one guideline -- both the AMP and Foldable/Traversable Proposal would pass this litmus test.

I'm mostly just running through active proposals and trying to understand the impact of such a policy, but so far I can't find anything that causes me to object.

I'm content to codify it as my own personal "best practice", and would be willing to see us as an organization draft it up into a form that other people could rely upon to get a sense of stability. In all of the above cases I think it actually improves upon the timeline a bit.

Lengthening the timelines above means we'll need to work harder on transferring institutional memory at the very least. Wiki and Trac items for these sorts of proposals will become even more important. It will become almost impossible to spawn a from-scratch Prelude-affecting proposal and finish it during one 3-year cycle tenure on the committee.

Ideas?

-Edward

Michael Snoyman

unread,
Oct 13, 2015, 12:42:55 AM10/13/15
to Edward Kmett, core-librari...@haskell.org
This sounds good to me. I like the idea of giving longer windows in general, and having that in mind may push us to think of better ways to avoid breakage. But I also agree that making this window a requirement would tie everyone's hands too much.

I'm also OK with cheating the clock. As I see it, we'd end up having *three* separate library maintainer goals necessary in order to make "cheating the clock" a burden:

* Maintain support for 3 GHC versions
* Support every GHC versions with -Wall and no CPP
* New requirement: easily have minimal package dependencies, without any cabal flag conditional business

Taking semigroups as the concrete example: people will be able to get backwards compatibility with -Wall clean builds and no CPP if they just add semigroups to their build-depends, correct?

--
You received this message because you are subscribed to the Google Groups "haskell-core-libraries" group.
To unsubscribe from this group and stop receiving emails from it, send an email to haskell-core-libr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Edward Kmett

unread,
Oct 13, 2015, 2:17:34 AM10/13/15
to Michael Snoyman, core-librari...@haskell.org
On Tue, Oct 13, 2015 at 12:42 AM, Michael Snoyman <mic...@snoyman.com> wrote:
This sounds good to me. I like the idea of giving longer windows in general, and having that in mind may push us to think of better ways to avoid breakage. But I also agree that making this window a requirement would tie everyone's hands too much.

I'm also OK with cheating the clock. As I see it, we'd end up having *three* separate library maintainer goals necessary in order to make "cheating the clock" a burden:

* Maintain support for 3 GHC versions
* Support every GHC versions with -Wall and no CPP
* New requirement: easily have minimal package dependencies, without any cabal flag conditional business

Taking semigroups as the concrete example: people will be able to get backwards compatibility with -Wall clean builds and no CPP if they just add semigroups to their build-depends, correct?

Correct. I'm not _that_ concerned with shaving down the timeline. I think I'd be happy either way. Even if we decided to accept cheating the clock, anything involved is going to see an 8.4 era 'final release' at the earliest. If haskell-prime is going to target a Haskell2017 report, then that may be a reason to push things forward to line up with an 8.4. If it winds up a Haskell2018, then that may be a reason to push it back.

Perhaps it is too much of reactionary move to try to give all of the ground here in the interest of soothing any nerves frayed by way of the AMP and FTP. That said, I think it wouldn't hurt to show that we can exercise restraint. There is after all a decent amount of overlap between the crowd upset about language changes and the crowd upset by dependencies. Showing that we _can_ manage the set of changes under consideration in a manner that satisfies all of those guidelines seems to me to be a worthy precedent to set.

-Edward 

Michael Snoyman

unread,
Oct 13, 2015, 2:33:11 AM10/13/15
to Edward Kmett, core-librari...@haskell.org
On Tue, Oct 13, 2015 at 9:17 AM, Edward Kmett <ekm...@gmail.com> wrote:
On Tue, Oct 13, 2015 at 12:42 AM, Michael Snoyman <mic...@snoyman.com> wrote:
This sounds good to me. I like the idea of giving longer windows in general, and having that in mind may push us to think of better ways to avoid breakage. But I also agree that making this window a requirement would tie everyone's hands too much.

I'm also OK with cheating the clock. As I see it, we'd end up having *three* separate library maintainer goals necessary in order to make "cheating the clock" a burden:

* Maintain support for 3 GHC versions
* Support every GHC versions with -Wall and no CPP
* New requirement: easily have minimal package dependencies, without any cabal flag conditional business

Taking semigroups as the concrete example: people will be able to get backwards compatibility with -Wall clean builds and no CPP if they just add semigroups to their build-depends, correct?

Correct. I'm not _that_ concerned with shaving down the timeline. I think I'd be happy either way. Even if we decided to accept cheating the clock, anything involved is going to see an 8.4 era 'final release' at the earliest. If haskell-prime is going to target a Haskell2017 report, then that may be a reason to push things forward to line up with an 8.4. If it winds up a Haskell2018, then that may be a reason to push it back.

Perhaps it is too much of reactionary move to try to give all of the ground here in the interest of soothing any nerves frayed by way of the AMP and FTP. That said, I think it wouldn't hurt to show that we can exercise restraint. There is after all a decent amount of overlap between the crowd upset about language changes and the crowd upset by dependencies. Showing that we _can_ manage the set of changes under consideration in a manner that satisfies all of those guidelines seems to me to be a worthy precedent to set.


Sounds reasonable. Just to get my opinion down clearly:

* Strong +1 to trying to keep to some kind of a three year plan
* Ambivalent as to whether we should allow "cheating the clock," and willing to gauge community reaction to individual proposals
* -1 on requiring that any specific policy be followed in all cases; the CLC needs flexibility to make exceptions in exceptional circumstances

Michael

Joachim Breitner

unread,
Oct 13, 2015, 3:54:29 AM10/13/15
to haskell-cor...@googlegroups.com
Hi,

Am Montag, den 12.10.2015, 20:42 -0400 schrieb Edward Kmett:
> In particular the discussion has been around the idea of trying to
> ensure that it is possible to write code in _some_ way without CPP
> that can run backwards for 3 releases of GHC, preferably in a -Wall
> safe manner.

Supporting -Wall hygiene is great, but if the policy prevents us from
giving people a useful warning, then we are giving up a useful
communication channel.

I suggest to add a new compiler warning
-Wfuture-incompatibilities
that is _not_ enabled by -Wall, and gives the developer a helpful
warning that there is something he can do to have less to do in the
future.

If it is too inconsistent to have a -Wsomething not in included in
-Wall, maybe it could be an "-f" flag instead.

Greetings,
Joachim

--
Joachim “nomeata” Breitner
ma...@joachim-breitner.dehttp://www.joachim-breitner.de/
Jabber: nom...@joachim-breitner.de • GPG-Key: 0xF0FBF51F
Debian Developer: nom...@debian.org

signature.asc

Simon Peyton Jones

unread,
Oct 13, 2015, 5:21:21 AM10/13/15
to Edward Kmett, Michael Snoyman, core-librari...@haskell.org

I’m delighted that the CLC is having this conversation – thank you.

 

One idea I floated in another thread is that of “batching” disruptive library changes, where by “disruptive” I mean things that are likely to force many library authors to make changes.  Would there be merit in

·         Discussing a change (eg the monad of no return)

·         Prototyping it

·         Designing it in detail

·         But then putting it in a pile of things to release in a batch

I think what people hate is a trickle of changes, each of which brings only minor benefit.   Having fewer disruptive updates would (a) reduce the change load, and (b) increase the payoff from the change.

 

How often is a batch?  Maybe every 2 or 3 years.  One is too short.

 

We need to find a way to reduce the pain of library change, without freezing the language so that past mis-steps are irredeemable.  Maybe this would be one way

 

Simon

Edward Kmett

unread,
Oct 13, 2015, 11:15:57 AM10/13/15
to Simon Peyton Jones, Michael Snoyman, core-librari...@haskell.org
On Tue, Oct 13, 2015 at 5:21 AM, Simon Peyton Jones <sim...@microsoft.com> wrote:

I’m delighted that the CLC is having this conversation – thank you.

 

One idea I floated in another thread is that of “batching” disruptive library changes, where by “disruptive” I mean things that are likely to force many library authors to make changes.  Would there be merit in

·         Discussing a change (eg the monad of no return)

·         Prototyping it

·         Designing it in detail

·         But then putting it in a pile of things to release in a batch

I think what people hate is a trickle of changes, each of which brings only minor benefit.   Having fewer disruptive updates would (a) reduce the change load, and (b) increase the payoff from the change.

 

How often is a batch?  Maybe every 2 or 3 years.  One is too short.


This is another strategy that could work, but it has some negative consequences of its own. (I spent a bunch of time talking through those with Gershom just last week when I counter proposed precisely this to him when he raised the 3-release policy idea to me.) Users would now get a 'sharp shock' every 2-3 years. It also means that that every other or every third year release becomes a messier affair. None of the changes we have in the wings that affect the Prelude in the end 'prototype' very well outside of GHC. MonadFail is a desugaring step. `semigroups` has acted as a laboratory for the Monoid changes for 7 years now, the extra Floating members.

But perhaps this is just a matter of perspective.

If we look at the proposals we're talking about though, then trying to match a 3-release policy actually gets us almost all the way there. Things come into base in 8.0 and then sit pretty stably for a couple of years before they can really evolve again / impact Prelude in 8.4, so it may just be that adopting a 3-release policy gets us most of the way there on a defacto basis in the short term.

The way the current schedule is working out some new stuff is going into base in 8.0, nothing Prelude facing happens in 8.2 at all, and in 8.4 more things will evolve as almost all of the plans hit at the same time, hopefully in sync with a Haskell Report. If the Haskell Report gets going on a regular clock (say Haskell2017 and Haskell2020) that also seems to suggest a natural 3 year cadence, just as an emergent phenomenon, even if not a formally decided one.

-Edward 
Reply all
Reply to author
Forward
0 new messages