pvp icon indicating copy to clipboard operation
pvp copied to clipboard

What is the goal of the PVP?

Open michaelpj opened this issue 1 year ago • 21 comments

It's not clear to me what the design of the PVP is trying to do. The Rationale section is suggestive, but not quite clear to me. In particular, I can see two possible goals:

  1. Keep packages compiling. The goal of the PVP is to identify which changes can cause downstream packages to no longer compile, and to signal those through appropriate version changes.
  2. Keep packages working. The goal of the PVP is to identify which changes can cause downstream packages to no longer work in some broader sense, and to signal those through appropriate version changes.

The reason why it would be helpful to make this explicit is that it makes it easier to work out what is following the "spirit of the PVP" in cases where the text might not be fully clear or cover a corner case.

The reason this came up was the discussion about warnings for missing methods. Schematically, this is a situation where:

  1. A user makes a change C to their library
  2. C can make downstream code behave in a way we might consider "broken", but will not stop it from compiling. GHC will, however, emit a warning.
  3. The proposal is to change the warning into an error.

Now, if our goal is goal 1, then this proposal changes what is a breaking change. Previously change C would not prevent downstream code from compiling, but now it will do. On the other hand, if our goal is goal 2, then arguably this was always a breaking change, since it can "break" downstream code.

But it's very hard to adjudicate such cases unless we know what the goal of the PVP is.

michaelpj avatar Oct 09 '23 16:10 michaelpj

Well...

Deprecation. Deprecated entities (via a DEPRECATED pragma) SHOULD be counted as removed for the purposes of upgrading the API, because packages that use -Werror will be broken by the deprecation. In other words the new A.B SHOULD be greater than the previous A.B.

It's not far fetched to extrapolate that any new warning from -Wdefault group counts as a breaking change. That is IMHO a bit too strict.

With TemplateHaskell though (or dependent types), the "keep packages working" and "keep packages compiling" difference is quite blurred, so I'd suggest to opt-out for "keep packages working" understanding when you are unsure whether your change is breaking or not.

But then there is e.g. error messages. Is changing error messages in say aeson a breaking change? Some tests somewhere may fail, sure. Are anything truly broken? I doubt.

So the truth is probably somewhere in between. "Keep maintainers sane".

phadej avatar Oct 09 '23 16:10 phadej

The PVP talks a lot about API versioning but doesn't really mention semantic side of changes, whether tests pass, etc. The PVP mandates a change in version when clients may get compilation error due to new changes, otherwise it doesn't require anything.

AFAIU the goal of the PVP is to keep thinks compiling when versions of dependencies are satisfied. Keeping things working is a much bigger goal.

sergv avatar Oct 09 '23 16:10 sergv

I don't think anyone knows, honestly. I don't believe PVP was designed properly. It's a versioning scheme and now we have to make decisions about user expectations, ecosystem and even the language (what is API). I believe it is ad-hoc.

hasufell avatar Oct 10 '23 02:10 hasufell

The PVP's origins are in the alternate policy which was a strawmanin the Eternal Compatibility article by Sven Moritz Hallberg in The Monad Reader in 2005: https://wiki.haskell.org/The_Monad.Reader/Issue2/EternalCompatibilityInTheory

In 2006, Bulat Ziganshin then proposed it be turned into a policy: https://mail.haskell.org/pipermail/haskell/2006-November/018762.html

Sven's motivation: "As a program module evolves, functions and other elements are added to, removed from, and changed in its interface. It is clear that programs importing the module (its dependants) will not be compatible with all versions. At least, each program is compatible with one version, the one the author originally used, and usually a few ones before and after that. But if a program is not continuously updated, with time, chances rise dramatically that one of its dependencies as installed on a given host system will be incompatible. Alas, the program cannot be used. This effect comprises a major source of bit rot."

Bulat's motivation: "library developer should just explicitly declare and obey some policy of incrementing library versions which will allow library user to select proper range of versions which are guaranteed to work with his code"

In both cases, the motivation was not quite specified enough to clearly read as goal 1 or goal 2 -- i.e. "guaranteed to work with" and "compatible with" can be taken to mean either goal. (Edit: and the PVP itself also speaks of compatibility, without having an a priori definition -- in a sense, it is the Haskell community's best effort at working out a common consensus on what compatibility itself means).

That said, to be clear, the PVP already specifies that any change to a typeclass is a breaking (major) change, which includes addition of new methods:

if any entity was removed, or the types of any entities or the definitions of datatypes or classes were changed, or orphan instances were added or any instances were removed, then the new A.B MUST be greater than the previous A.B

So I think in practice we have something more than "just compiles" but less than "will never make anything go wrong" and where precisely to draw that line is the job first of the pvp maintainers, and second of package authors themselves. Which is to say that the PVP specifies minimum criteria slightly more strict than option 1, and package maintainers may choose to go beyond these criteria in cases they feel appropriate.

I would also add that whatever the flaws (and I am happy to see so many people interested in resolving and improving them), in my experience and investigation, the PVP is better designed and more carefully thought through already than any alternative policy in any other ecosystem.

gbaz avatar Oct 10 '23 04:10 gbaz

and where precisely to draw that line is the job first of the pvp maintainers

It seems like the second time you postulate responsibilities for PVP maintainers.

Let me be very clear here: my opinion remains that this is not our job. And I will make no effort in developing those goals.

All proposals trying to extend PVP beyond the versioning scheme part will get a -1 vote from me.

hasufell avatar Oct 10 '23 04:10 hasufell

Let me be very clear here: my opinion remains that this is not our job. And I will make no effort in developing those goals.

I have been a maintainer on the PVP repo for a long time, as have other hackage trustees. Bodigrim asked if the CLC could take it over responsibility in consultation with us, and we acquiesced. If you don't want to be a part of that, feel free to walk away from this set of responsibilities. It makes no sense to have somebody as a maintainer who disagrees with the fundamental purpose and nature of the PVP, and the best thing for you to do in this situation would be to recuse yourself.

gbaz avatar Oct 10 '23 05:10 gbaz

Let me be very clear here: my opinion remains that this is not our job. And I will make no effort in developing those goals.

I have been a maintainer on the PVP repo for a long time, as have other hackage trustees. Bodigrim asked if the CLC could take it over responsibility in consultation with us, and we acquiesced. If you don't want to be a part of that, feel free to walk away from this set of responsibilities. It makes no sense to have somebody as a maintainer who disagrees with the fundamental purpose and nature of the PVP, and the best thing for you to do in this situation would be to recuse yourself.

I think that is incredibly rude (for the second time) and it seems to me you're trying to impose your understanding of PVP to the rest of the committee/maintainers.

If you've followed other committees like CLC or GHC SC you'll see that there are many instances of disagreements between committee members. Some CLC members might not believe that any addition to base is a good idea and vote -1 for all of them. That is democracy.

I have laid out my opinion in very great detail and provided reasoning.

I think it's fair to keep the existing wording around API breakage as a historical "best effort" description, but any addition to it will get us into more trouble about a language that is constantly evolving and not properly specified.

As to your suggestion: I will not recuse myself and I ask you to stop suggesting that.

hasufell avatar Oct 10 '23 07:10 hasufell

@michaelpj I'm terribly sorry for having triggers this. @gbaz for my understanding, can you outline what your view on the "fundamental purpose and nature of the PVP" is? @hasufell maybe you can also outline what your view on the "fundamental purpose and nature of the PVP" is?

Maybe if there is a disagreement in understanding we can amend?

angerman avatar Oct 10 '23 07:10 angerman

@hasufell maybe you can also outline what your view on the "fundamental purpose and nature of the PVP" is?

It is a "Package Versioning Policy" as described on the front page.

It goes on specifying the rationale, which is

The goal of a versioning system is to inform clients of a package of changes to that package that might affect them, and to provide a way for clients to specify a particular version or range of versions of a dependency that they are compatible with.

In the later section it says

What is missing from this picture is a policy that tells the library developer how to set their version numbers, and tells a client how to write a dependency that means their package will not try to compile against an incompatible dependency. For some time there has been an informal policy in use in the Haskell community, but it became clear that we were running into trouble with incorrectly-specified dependencies and unbuildable packages, so this page is an attempt to formalize the policy.

Alright. This sounds like an attempt to specify what "API" means. It says here "is an attempt to formalize the policy". I've made clear in other threads that I believe this attempt has failed and I'd either:

  1. freeze the state of this attempt and stop amending to it
  2. remove it entirely (that has not gotten a majority vote)

As a committee member expected to vote on PVP matters I believe it's well within my right to adhere to 1 through my way of voting.

@gbaz has failed to convince me otherwise through demonstrating how we would:

  • discuss and distill what is "API" in collaboration with GHC HQ and GHC SC
  • maintain those properties in light of constant language evolution
  • develop the required tools that are promised in the FAQ and actually fulfill the goal of helping library maintainers choose correct version numbers
  • get to a state where PVP can be enforced on hackage
  • explain who's going to fund this humongous project (I already lost all interest after these interactions)

Instead, all I see is "please leave the comittee if you don't agree with me". I'm sorry to disappoint. I'll need better arguments.

hasufell avatar Oct 10 '23 07:10 hasufell

Let's all stay polite here! We are all on the same side.

The PVP is not like the US constitution: a fixed document where we seek to divine the intentions of the authors. It is our living document. All we need do is to figure out what we want it to say.

As I understand it, if I change the semantics of an exported function (without changing its type), I should do a major version bump. For example, if I changed sort to sort backwards, I should do a major version bump. I suspect that there would be broad consensus on this point.

That sounds more like goal (2): keep clients working. Oddly, the actual words in the PVP spec do not mention changes in semantics/behaviour, but it is absolutely explicit in the diagram in the "decision tree" section, which says "Did the behavior of any exported functions change? Yes => major version bump."

Covering semantics is very much in the spirit of our agreed GHC base library proposal, where Section 3 describes the API that the CLC curates as covering semantics.

That said, it's clear that a promise to "keep clients working" is un-implementable. E.g. if I optimise a function so that it runs a lot faster, a client that depends on it running slowly will break. Fixing an outright bug is another example: it's a semantic change, and could conceivably break a client, but I think it's arguable that you should not feel obliged to make a major version bump every time you fix a bug.

So I don't think the PVP can ever be perfect. It can't tell you exactly what to do. But it can still be very helpful in setting general criteria, and laying down precise rules where (but only where) that is possible.

Concretely, my suggestion would be to add a numbered item in the "Version numbers" section, that covers changes in semantics.

simonpj avatar Oct 10 '23 09:10 simonpj

@gbaz for my understanding, can you outline what your view on the "fundamental purpose and nature of the PVP" is?

The purpose and nature of the PVP in my view was elaborated above. The PVP historically, in the citations I give, and also in the body of the text, both specifies the syntax of version numbers, and a best-effort at rules which delineate a minimum criteria by which some changes are considered "breaking" or "non-breaking" and thus would or would not require a major version number bump. As the text of the PVP rationale states, it provides "a policy that tells the library developer how to set their version numbers, and tells a client how to write a dependency that means their package will not try to compile against an incompatible dependency."

The rub, which Simon observes, is that this cannot be anything but a "best effort" and lay down rules where possible.

I tend to agree that an explicit rule covering changes in semantics would be worthwhile, and this has been discussed at prior times, eg https://github.com/haskell/pvp/issues/41.

I think the guidance would have to be please use your head however. What we can accomplish by explicit rules firmly is (at best) only that packages keep compiling, but we can also encourage that changes that might otherwise be "morally breaking" (such as reversing sort direction) also trigger major version bumps.

gbaz avatar Oct 10 '23 14:10 gbaz

@simonpj

So I don't think the PVP can ever be perfect. It can't tell you exactly what to do. But it can still be very helpful in setting general criteria, and laying down precise rules where (but only where) that is possible.

This doesn't feel sufficient to me, unless the GHC SC wants to co-maintain PVP and oversee the "what is API?" part of it.

To re-iterate: I think this is significant effort. What is API in light of TypeApplications, LinearTypes, upcoming dependent types, etc. etc. GHC SC is free to innovate however they see fit and CLC now becomes the downstream consumer that needs to figure out how to define "API". That doesn't seem fair and I question that anyone has bandwidth for that particular part of the spec.

So I'm more interested in how you suggest this work is being done, continuously. A joint effort? A working group?

hasufell avatar Oct 10 '23 15:10 hasufell

To re-iterate: I think this is significant effort

What is "this"? My suggestion is as above: add an extra item covering semantics to the PVP. (I'd be happy with adding a more general "use your head" principle, with an attempt to explain what that means.)

I know that you don't think that is satisfactory, but it's (a bit) better than the status quo, isn't it? And it's very cheap to implement: excellent cost/benefit ratio.

Perhaps there is a much larger task that we could undertake together, but it'd have to compete with the other tasks that we are all working on, so we'd have to be convinced that the significant effort was going to have a good cost/benefit ratio.

simonpj avatar Oct 10 '23 15:10 simonpj

What is "this"?

Maintaining a satisfactory and up-to-date definition of what constitutes "API" in light of the latest GHC language.

My opinion is that piecemeal additions to the spec will not fix the underlying problem that Haskell users still are confused about how to manage their versions.

So I'm very skeptical unless someone makes a suggestion on how to maintain the definition of what constitutes API. This has not happened. As such I will keep my conservative stance.

Perhaps there is a much larger task that we could undertake together, but it'd have to compete with the other tasks that we are all working on, so we'd have to be convinced that the significant effort was going to have a good cost/benefit ratio.

Precisely. I'm also not sure the cost/benefit ratio is good enough to maintain the "API definition" part at all, which is why I've previously suggested to remove it completely, so someone else can maybe maintain it better.

hasufell avatar Oct 10 '23 15:10 hasufell

Precisely. I'm also not sure the cost/benefit ratio is good enough to maintain the "API definition" part at all, which is why I've previously suggested to remove it completely, so someone else can maybe maintain it better.

OK great.

  • I (and I believe @gbaz) propose to add some words about semantics.
  • You propose to remove some words. Can you make that more specific? What words exactly would you like to remove?
  • Neither of us is proposing that we shoulud undertake the much larger task of "Maintaining a satisfactory and up-to-date definition of what constitutes "API" in light of the latest GHC language". (I'm not even quite sure what that means -- but it doesn't matter since neither of us is proposing to do it.)

That gives us two extant proposals, both relatively cheap to execute on. We could flesh them out with more specific language, and the the PVP curators can decide. Would that be helpful?

simonpj avatar Oct 10 '23 16:10 simonpj

I haven't yet added a semantics PR, because the wording could use some discussion, but I just opened a PR (https://github.com/haskell/pvp/pull/56) to handle the other concern -- i.e. providing general guidance on how to consider changes that the PVP has not yet been explicitly extended to cover.

gbaz avatar Oct 10 '23 16:10 gbaz

This is the sort of guidance that I was after, but I do partially agree with @hasufell that maybe this isn't part of the spec per se. The way I was thinking about it was:

  • We have a goal which we are trying to achieve (packages keep compiling)
  • We have a spec which people can follow, which we design to achieve the goal
  • The spec is imperfect, and in such cases people may wish to "use their heads" and try to do what achieves the goal

But saying that the spec itself contains the statement "try to achieve the goal" is maybe a bit confusing.

I do think that the goal itself is a moving target. If GHC changes to make some random thing breaking, then the PVP-as-currently-specified will no longer keep packages compiling, and so will fail at the goal. And that then tells us what to do: change the spec.

michaelpj avatar Oct 11 '23 20:10 michaelpj

@michaelpj let me add more confusion. The Haskell language report doesn't demand that Haskell is a compiled language, IMO, although it seems to lazily assume it is in some sections:

This report defines the syntax for Haskell programs and an informal abstract semantics for the meaning of such programs. We leave as implementation dependent the ways in which Haskell programs are to be manipulated, interpreted, compiled, etc. This includes such issues as the nature of programming environments and the error messages returned for undefined programs (i.e. programs that formally evaluate to ⊥).

As such, we could have a Haskell "compiler" that only interprets. What is the meaning of the PVP spec in that case?

I know these days it's very popular to say "GHC is the only Haskell compiler, let's stop trying to adhere to the spec or develop it". I feel very strongly about this and I'm against tying the PVP spec to GHC. In fact it shouldn't be tied to Haskell either (but for different reason).

We could split it out into multiple parts (sorry for reiterating, but it is relevant again):

  • PVP core: deals with versioning only
  • Haskell PVP: deals with definition of what API means and applies the PVP to Haskell
  • hackage policy: decides what is enforced and can add more restrictions or meaning to certain parts (e.g. caret operator)

Then we could also have separate maintainership. I believe the second part should not be maintained by hackage trustees or CLC, but by GHC HQ and GHC SC. It doesn't seem they are particularly interested, though.

CLC should only be involved in PVP core, imo. But my feeling is that not many feel strongly about the importance of PVP, so splitting the document and incurring more maintenance is unpopular. And I think that's why it's not a good spec.

hasufell avatar Oct 12 '23 02:10 hasufell

But saying that the spec itself contains the statement "try to achieve the goal" is maybe a bit confusing.

Legal contracts often have umbrella clauses that state rules for things not expressly covered. This is no different. I.e. it says "when we don't yet specify how to achieve the goal, make an effort to do so anyway." It does not cover things expressly enumerated, so it isn't self-referential so much as "open". (i.e. it is not impredicative).

As such, we could have a Haskell "compiler" that only interprets. What is the meaning of the PVP spec in that case?

I think it would be a reasonable improvement to replace compile with "parse and typecheck successfully" or to note that for the purposes of the PVP when working with an interpreter such as hugs that this is the intended meaning of "compile".

gbaz avatar Oct 12 '23 02:10 gbaz

I believe the second part should not be maintained by hackage trustees or CLC, but by GHC HQ and GHC SC. It doesn't seem they are particularly interested, though.

More over, I don't see GHC HQ or SC well equipped for such task. And a separate committee just for PVP would not have enough work to justify lifecycling costs.

We can very well separate concerns and follow your suggestion to split PVP document into three levels (the first of which is just a single sentence "Version consists of 4 digits, first two are to indicate a major version and be bumped for breaking changes, the third one is for other API changes, the fourth is for packaging changes"). I don't feel however that granting control to three different committees could work well. In a different reality, 20 years earlier or under SLURP proposal, it would make much more sense, but not in our current state.

and where precisely to draw that line is the job first of the pvp maintainers

It seems like the second time you postulate responsibilities for PVP maintainers. Let me be very clear here: my opinion remains that this is not our job. All proposals trying to extend PVP beyond the versioning scheme part will get a -1 vote from me.

@hasufell as far as I understand your objection is that "where to draw that line" is a job for "Haskell/Hackage-specific PVP" maintainers, and you want to be responsible only for "language-agnostic PVP" maintenance. Fair enough. But someone still has to take responsibility for the former, and I'm not sure what's the point of mechanically downvoting such efforts. This would not make PVP language-agnostic, it will just keep it stagnating.

Bodigrim avatar Oct 25 '23 20:10 Bodigrim

as far as I understand your objection is that "where to draw that line" is a job for "Haskell/Hackage-specific PVP" maintainers, and you want to be responsible only for "language-agnostic PVP" maintenance. Fair enough. But someone still has to take responsibility for the former, and I'm not sure what's the point of mechanically downvoting such efforts. This would not make PVP language-agnostic, it will just keep it stagnating.

Hm. I don't know whether I agree.

For example, as a PVP maintainer I can see various valid opinions:

  1. the "define Haskell API" question can evolve gradually (as @simonpj suggested)
  2. it's the job of CLC to define Haskell API and they should do so grandiosely, rather than in a reactive manner
  3. PVP only deals with a proper standard and the last one is Haskell2010
  4. PVPs efforts of defining API are incomplete, but should not be extended. They may serve as an inspiration. Other projects may build upon them.

In fact 2, 3 and 4 all would suggest very conservative voting towards gradual additions.

I hope that makes my stance more clear. I'm strongly against proposal 1.

hasufell avatar Oct 26 '23 05:10 hasufell