haskell / core-libraries-committee

95 stars 16 forks source link

Clarify 3-release policy #228

Closed hasufell closed 5 months ago

hasufell commented 12 months ago

The following discussion sparked my interest: https://gitlab.haskell.org/ghc/ghc/-/issues/24154#note_534965

Which linked to: https://gitlab.haskell.org/haskell/prime/-/wikis/libraries/3-release-policy

I have never heard of it. Was this written by a former CLC?

The policy says:

Changes to basic libraries are planned and implemented so that, at any time, it is possible to write code that works with the latest three releases of GHC and base, without resorting to CPP, and without causing warnings even when compiled with -Wall. Such code may not necessarily be idiomatic, though.

But doesn't mention what "latest three releases" means... minor? Major? Chronological?

Can we get some clarification about this document?

phadej commented 12 months ago

FWIW, https://gitlab.haskell.org/haskell/prime/-/wikis/libraries/3-release-policy starts with

Changes to the basic libraries, especially the Prelude, can be disruptive

So the three release policy can be (and IMO that was the initial intention) understood to mean changes to the Prelude. Changes somewhere else in base could be more "distributive" (i.e. cause warnings under -Wall). The page does say (emphasis mine)

The primary scope of this policy is the Prelude, as it affects the largest number of library authors. For other modules of base and other basic libraries, it is desirable to follow the guideline, if possible.

The MonadFail example was also a change affecting Prelude, thus 3-release-policy.


EDIT: Also the policy was written when GHC release cadence was around one major version a year. I think it should be 3-year-policy (or maybe just two years, but in years nevertheless). Release, as @hasufell mentions, is very vague measurement unit of "time".

simonpj commented 10 months ago

It would be helpful to clear up this thread -- see discussion on https://github.com/ghc-proposals/ghc-proposals/pull/625.

Especially this comment: https://github.com/ghc-proposals/ghc-proposals/pull/625#issuecomment-1876731498, which suggests that when

it is hard to see how to implement a warning-free 3-release policy.

gbaz commented 10 months ago

The releases were intended to be major releases.

I've long felt it should be amended to be "last three major releases, or last two years of major releases, whichever is longer"

simonpj commented 10 months ago

@Bodigrim once the CLC has agreed what it wants, it would be super-helpful to move the three-release policy out of the Haskell Prime wiki, and make it part of the CLC home page or CLC proposals process page. At the moment it's not clear whether or not the CLC espouses a three-release policy.

Clarity is good! Thanks.

Bodigrim commented 10 months ago

At the moment it's not clear whether or not the CLC espouses a three-release policy.

Correct but useless answer: CLC accepted the three-release policy as a guideline in 2015.

Practical answer: in the current division of labor 3-release policy is largely meaningless for CLC purposes. For example, one can nuke entire Prelude in one go and still be compliant: it is possible to write a code that works without warnings just importing entities from their home modules. One can reshuffle any non-wired-in type class as well - it is sufficient to offer the original one from a compatibility module somewhere.

It's only entities wired in GHC which matter for 3-release policy, such as Applicative-Monad, Monad-Fail or Monad-of-No-Return proposals, because you cannot simply say "here is a new class Monad; import Control.Monad.Old if you need the old one", because all do-notation will break. But nowadays changes of such sort fall under GHC SC purview (or combined purview of CLC and GHC SC), so it would make more sense for GHC SC to embrace the three-release policy.

Bodigrim commented 10 months ago

it is hard to see how to implement a warning-free 3-release policy.

I agree. If GHC SC is looking to adopt a policy of such kind, I recommend to through away "warning-free" limitation.

My experience with the 3-release policy is that "warning-free" is a misnomer: if there are no warnings, no one cares to migrate anywhere, so you are just wasting cycles.

simonpj commented 10 months ago

Correct but useless answer: CLC accepted the three-release policy as a guideline in 2015.

Aha. Would be possible to modify the CLC's home page to say so, and include the actual guideline?

Practical answer: in the current division of labor 3-release policy is largely meaningless for CLC purposes

@bodigrim, you are right if you consider only the three-release policy, but I think not-right if you add the CLC's stability goals.

I believe that an implicit CLC goal is:

You straw-man example of nuking the Prelude would not satisfy (CLC-GR1).

One cannot always satisfy (CLC-GR1). For example, simply adding an export sortWith to Data.List will break any package that imports Data.List and defines its own sortWith. So one might imagine adding

For example, the client could say import Data.List hiding( sortWith ). (But note that would provoke a warning in the before-change case, where Data.List does not export sortWith).

We are trying to articulate GHC's stability goals. Since GHC depends on base, any goals GHC articulates must in turn rely on the CLC's goals.

So perhaps I can broaden this ticket to ask: would it be possible for the CLC to articulate the stability goals it follows? As we have seen, it's surprisingly tricky, and hence all the more important to state explicitly, rather than just assume implicitly. Thanks!

Bodigrim commented 10 months ago

Strangely, I can't see this criterion written down anywhere.

That's because you just invented it ;)

Since GHC depends on base, any goals GHC articulates must in turn rely on the CLC's goals.

You can always express GHC SC principles as conditional on CLC actions, e. g., "GR1. If CLC did not break working code, GHC SC also aspires not to break it in a given release".

So perhaps I can broaden this ticket to ask: would it be possible for the CLC to articulate the stability goals it follows?

Let's keep the scope of this ticket as intended originally.

I'm largely skeptical about such policies for many reasons, and the prolonged discussion at https://github.com/ghc-proposals/ghc-proposals/pull/625 suggests that this is not an investment I can afford. One can suggest CLC a stability policy, but please be prepared for a very long discussion. I'm also likely to vote down any such proposal purely on the grounds of CLC institutional neutrality.

Sorry, I don't mean it to sound unwelcoming, but I'm really way too overwhelmed recently.

gbaz commented 10 months ago

For example, one can nuke entire Prelude in one go and still be compliant: it is possible to write a code that works without warnings just importing entities from their home modules.

Not exactly. Even in the case of removing a single definition from the prelude, the 3-release policy kicks in. If the prelude exports doWombat and we want you to get that now from Control.Wombat then it must first exist in Control.Wombat for at least two releases before you remove it from the prelude. You might say "oh that's an obvious modest thing and we'd do that anyway" and sure. But that was the point of the 3-release policy -- to codify things that are usually that obvious and modest.

hasufell commented 10 months ago

You can always express GHC SC principles as conditional on CLC actions, e. g., "GR1. If CLC did not break working code, GHC SC also aspires not to break it in a given release".

I second that.

Although I'm much more bullish about CLC having a stability policy (even if a future CLC tears it down).

simonpj commented 10 months ago

But that was the point of the 3-release policy -- to codify things that are usually that obvious and modest

Yes that's the point exactly. Whether we say so or not, the CLC does have policies, which it uses to evaluate proposals. The only question is whether such policies are written down or not.

I favour writing them down. If they remain unwritten, proposal authors may be unaware of them, or misunderstand them; and even committee members might have different understandings, especially as membership changes.

I'm largely skeptical about such policies for many reasons, and the prolonged discussion at https://github.com/ghc-proposals/ghc-proposals/pull/625 suggests that this is not an investment I can afford.

I am deeply sympathetic to this point of view. And yet in the long term, the paper-cut costs of having only implicit folk-lore policies all add up.

phadej commented 10 months ago

You can always express GHC SC principles as conditional on CLC actions, e. g., "GR1. If CLC did not break working code, GHC SC also aspires not to break it in a given release".

This highlights coupling which shouldn't be there. If base and GHC (as a language and its implementation) were independent, than GHC stability principles won't need to mention base / CLC at all (base would be a library like any other, say transformers or aeson).

One can argue that it was a mistake to decouple ownership of GHC and base, but here we are now. it's now probably better to embrace the decoupling than not to.

Bodigrim commented 10 months ago

Any dependency of ghc-the-library is not reinstallable at the moment, so base curated by CLC is not fundamentally different in its impact on users from bytestring or containers. Maybe the wording could be "GR1. GHC SC aspires not to break things on its own (but things might be broken by other actors)".

phadej commented 10 months ago

urated by CLC is not fundamentally different in its impact on users from bytestring or containers.

Indeed, and Simon is not asking bytestring or containers maintainers to write the stability policy!

gbaz commented 10 months ago

"Any dependency of ghc-the-library is not reinstallable at the moment, so base curated by CLC is not fundamentally different in its impact on users from bytestring or containers"

I don't understand this. Perhaps we use "reinstallable" to mean different things? I tend to think of it as meaning "one can install a new version" not "one can delete the existing installation at the same version and replace it." So I can't install any version of base -- I'm stuck with the one shipped with my ghc. I can install a new bytestring or containers -- I just can't stomp the existing one in the process.

That said, I understand if it is too much work for the CLC to write a new stability policy at this point in time, and I think that GHC's policy can simply have a "carve out". However, the 3 release policy is an existing guideline with a long history by now, and migrating it to a less hidden home would be welcome.

hasufell commented 9 months ago

I'm unsure how the 3-release policy works with deprecations and generally find that the "without CPP" requirement is a bit strong. What exactly is the motivation?

Bodigrim commented 9 months ago

Even in the case of removing a single definition from the prelude, the 3-release policy kicks in. If the prelude exports doWombat and we want you to get that now from Control.Wombat then it must first exist in Control.Wombat for at least two releases before you remove it from the prelude.

One can nuke a definition from base entirely and remain compliant with the 3-release policy by asking every user to inline it in their code. Evil? Sure. Prohibited? No.

Perhaps we use "reinstallable" to mean different things? I tend to think of it as meaning "one can install a new version" not "one can delete the existing installation at the same version and replace it." So I can't install any version of base -- I'm stuck with the one shipped with my ghc. I can install a new bytestring or containers -- I just can't stomp the existing one in the process.

As soon as your build plan involves ghc-the-package (which happens as soon as your tests depend on doctest, for instance) you cannot install a new version of bytestring or containers.

Bodigrim commented 9 months ago

I think that the immediate questions in this thread have been answered.

I personally do not believe that mentioning 3-release policy in current CLC documents is a good use of screen space, because, as explained above, due to the division of labor before CLC and GHC SC, its implications are irrelevant to CLC proposals. But if someone feels strongly about it and is motivated enough to raise a PR with detailed discussion, feel free to do so.

If there are no more concerns to discuss, I'll close this issue at the end of February.

hasufell commented 9 months ago

So we're comfortable to defer this type of policy entirely to GHC HQ/SC and acknowledge they may just abandon it?

gbaz commented 9 months ago

I don't find the rules-lawyering above persuasive. The idea that "backwards compat" doesn't mean anything because users can just be instructed to inline everything not wired-in obviously runs against the spirit if not letter of the policy. This is especially the case with datatypes and typeclasses because wired-in or not, they are used across multiple packages so users can't simply choose to each inline them individually and have those packages work together.

I thin it is fine to say the CLC at this time can't work to improve the policy or craft a more specific one.

But it remains the policy, it remains relevant, and so should be added as the policy that has existed for many years and never been overturned in some more prominent place in the CLC documentation.

I appreciate it is an imperfect policy -- but it is one of the only policies the CLC has, and it would be wrong to do a "backdoor deprecation" of it by attempting to either hide it or argue it out of existence.

Bodigrim commented 9 months ago

I'm not trying to be lawyerish here. The above is my honest reading of the policy and this is how I apply it. After all it says "such code may not necessarily be idiomatic".

I do not feel like arguing about a spirit of the policy is productive. If we find ourselves disagreeing on it, my view is that we should stick to the lowest common denominator.

gbaz commented 9 months ago

I'm not arguing for changing it, or even having a massive debate on its interpretation. It has been a guiding principle of the CLC and should, absent any other changes, be in a location connected to current CLC documentation, that's all.

(Even in the above arguments, you note that it may well apply to GHC steering decisions, but some of those may also be joint decisions with the CLC -- so its still worthwhile from the CLC side even if we fully accept the narrow scenarios you present for its application).

Bodigrim commented 5 months ago

My recollection is that out of 200+ proposals here at most 2 or 3 ever mentioned 3-release policy, so I'm not sure how much of guiding principle it is in practice, for the modern incarnation of CLC.

In April 2024 CLC approved #262 to clarify that we do not recognise warnings as breaking changes, dilluting meaning of 3-release policy even further.

Let me close this; as suggested above, if someone feels motivated enough, potential changes to the documentation can be raised and discussed in a PR.