
I'm a little bit uncertain of the PVP guidelines in a certain case[1], so I'd like to get some guidance/clarity. Suppose I have a library which provides the function: myFunction :: IO () myFunction = forever $ putStrLn "Still here" >> threadDelay 10^6 Later, I realize (or someone points out to me) that I've over-specified the type signature, and really myFunction should be: myFunction :: IO a In this case, does the PVP specify that we should have a minor or a major version bump? I'm not certain if this counts as a breaking change or not. [1] https://github.com/fpco/streaming-commons/pull/13

I think the question is: can this change cause existing code to stop
compiling (perhaps assuming people aren't using -Werror)? I don't think it
can but perhaps generalizing the type could make type inference fail
somewhere due to an ambiguous type.
We really need a PVP guide that just lists lots of examples, each with a
note of what kind of change it is (i.e. major, minor, or patch).
On Mon, Dec 15, 2014 at 10:00 AM, Michael Snoyman
I'm a little bit uncertain of the PVP guidelines in a certain case[1], so I'd like to get some guidance/clarity. Suppose I have a library which provides the function:
myFunction :: IO () myFunction = forever $ putStrLn "Still here" >> threadDelay 10^6
Later, I realize (or someone points out to me) that I've over-specified the type signature, and really myFunction should be:
myFunction :: IO a
In this case, does the PVP specify that we should have a minor or a major version bump? I'm not certain if this counts as a breaking change or not.
[1] https://github.com/fpco/streaming-commons/pull/13
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

To be nitpicky myFunction >>= \() -> x would break. It's unlikely that
anyone uses it like this, but I've been on the safe side in the past and
major bumped for cases like this. I think it's unwise to take shortcuts in
the other direction.
- Adam
On Mon, Dec 15, 2014 at 10:44 AM, Johan Tibell
I think the question is: can this change cause existing code to stop compiling (perhaps assuming people aren't using -Werror)? I don't think it can but perhaps generalizing the type could make type inference fail somewhere due to an ambiguous type.
We really need a PVP guide that just lists lots of examples, each with a note of what kind of change it is (i.e. major, minor, or patch).
On Mon, Dec 15, 2014 at 10:00 AM, Michael Snoyman
wrote: I'm a little bit uncertain of the PVP guidelines in a certain case[1], so I'd like to get some guidance/clarity. Suppose I have a library which provides the function:
myFunction :: IO () myFunction = forever $ putStrLn "Still here" >> threadDelay 10^6
Later, I realize (or someone points out to me) that I've over-specified the type signature, and really myFunction should be:
myFunction :: IO a
In this case, does the PVP specify that we should have a minor or a major version bump? I'm not certain if this counts as a breaking change or not.
[1] https://github.com/fpco/streaming-commons/pull/13
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Woah i shouldn't be nitpicky when I'm confused :-) Sorry.
On Mon, Dec 15, 2014 at 1:16 PM, Adam Bergmark
To be nitpicky myFunction >>= \() -> x would break. It's unlikely that anyone uses it like this, but I've been on the safe side in the past and major bumped for cases like this. I think it's unwise to take shortcuts in the other direction.
- Adam
On Mon, Dec 15, 2014 at 10:44 AM, Johan Tibell
wrote: I think the question is: can this change cause existing code to stop compiling (perhaps assuming people aren't using -Werror)? I don't think it can but perhaps generalizing the type could make type inference fail somewhere due to an ambiguous type.
We really need a PVP guide that just lists lots of examples, each with a note of what kind of change it is (i.e. major, minor, or patch).
On Mon, Dec 15, 2014 at 10:00 AM, Michael Snoyman
wrote: I'm a little bit uncertain of the PVP guidelines in a certain case[1], so I'd like to get some guidance/clarity. Suppose I have a library which provides the function:
myFunction :: IO () myFunction = forever $ putStrLn "Still here" >> threadDelay 10^6
Later, I realize (or someone points out to me) that I've over-specified the type signature, and really myFunction should be:
myFunction :: IO a
In this case, does the PVP specify that we should have a minor or a major version bump? I'm not certain if this counts as a breaking change or not.
[1] https://github.com/fpco/streaming-commons/pull/13
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Almost any API change can break existing code. For example, adding a new function can break code. I thought the guiding principle for PVP was how likely it is that a piece of client code will break, not if that's theoretically possible. On 15/12/14 11:44, Johan Tibell wrote:
I think the question is: can this change cause existing code to stop compiling (perhaps assuming people aren't using -Werror)? I don't think it can but perhaps generalizing the type could make type inference fail somewhere due to an ambiguous type.
We really need a PVP guide that just lists lots of examples, each with a note of what kind of change it is (i.e. major, minor, or patch).
On Mon, Dec 15, 2014 at 10:00 AM, Michael Snoyman
mailto:michael@snoyman.com> wrote: I'm a little bit uncertain of the PVP guidelines in a certain case[1], so I'd like to get some guidance/clarity. Suppose I have a library which provides the function:
myFunction :: IO () myFunction = forever $ putStrLn "Still here" >> threadDelay 10^6
Later, I realize (or someone points out to me) that I've over-specified the type signature, and really myFunction should be:
myFunction :: IO a
In this case, does the PVP specify that we should have a minor or a major version bump? I'm not certain if this counts as a breaking change or not.

In other words, the PVP is not rigorously specified, and this particular
question is uncharted territory.
My initial interpretation of the PVP is one of subtyping. I consider
loosening type signatures as a minor version bump, because the new thing
still fits into holes shaped like the old thing.
However, seen a different way, you could say that previously, IO () was
just a value, but now, it's (forall a. IO a), which is basically (a:Type ->
IO a), if Haskell were dependently typed. Going from a value to a function
is definitely a major change.
Was that sufficiently unhelpful? :P I think my conclusion is perhaps that
the PVP should remain undefined on this particular question, since I see no
obvious answer. Or, since the PVP already encourages a cautious
over-estimate of what constitutes a breaking change, perhaps we should go
with this fallback: "when in doubt, call it a major change."
-- Dan Burton
On Mon, Dec 15, 2014 at 9:10 AM, Roman Cheplyaka
Almost any API change can break existing code.
For example, adding a new function can break code.
I thought the guiding principle for PVP was how likely it is that a piece of client code will break, not if that's theoretically possible.
On 15/12/14 11:44, Johan Tibell wrote:
I think the question is: can this change cause existing code to stop compiling (perhaps assuming people aren't using -Werror)? I don't think it can but perhaps generalizing the type could make type inference fail somewhere due to an ambiguous type.
We really need a PVP guide that just lists lots of examples, each with a note of what kind of change it is (i.e. major, minor, or patch).
On Mon, Dec 15, 2014 at 10:00 AM, Michael Snoyman
mailto:michael@snoyman.com> wrote: I'm a little bit uncertain of the PVP guidelines in a certain case[1], so I'd like to get some guidance/clarity. Suppose I have a library which provides the function:
myFunction :: IO () myFunction = forever $ putStrLn "Still here" >> threadDelay 10^6
Later, I realize (or someone points out to me) that I've over-specified the type signature, and really myFunction should be:
myFunction :: IO a
In this case, does the PVP specify that we should have a minor or a major version bump? I'm not certain if this counts as a breaking change or not.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On 2014-12-15 20:24, Dan Burton wrote:
Was that sufficiently unhelpful? :P I think my conclusion is perhaps that the PVP should remain undefined on this particular question, since I see no obvious answer. Or, since the PVP already encourages a cautious over-estimate of what constitutes a breaking change, perhaps we should go with this fallback: "when in doubt, call it a major change."
I'd add that the level of caution should definitely also be a function of the number of (published) reverse dependencies that the package in question has. (I wouldn't be too worried about unpublished reverse dependencies; if you keep your code hidden from the world, it's *your* problem to deal with breakage that cannot be foreseen by the authors of your dependencies.) Regards,

On Mon, Dec 15, 2014 at 8:24 PM, Dan Burton
Or, since the PVP already encourages a cautious over-estimate of what constitutes a breaking change, perhaps we should go with this fallback: "when in doubt, call it a major change."
I think this makes sense. Unless you can convince yourself that the change doesn't break backwards compatibility (i.e. doesn't break code that uses only qualified imports and/or explicit import lists) bump the major version number. We should take the guesswork out of this. We should enumerate all possible API change variations and the corresponding version number bump. Even better, we should have a tool (like Elm has) that does so for you.
-- Dan Burton
On Mon, Dec 15, 2014 at 9:10 AM, Roman Cheplyaka
wrote: Almost any API change can break existing code.
For example, adding a new function can break code.
I thought the guiding principle for PVP was how likely it is that a piece of client code will break, not if that's theoretically possible.
On 15/12/14 11:44, Johan Tibell wrote:
I think the question is: can this change cause existing code to stop compiling (perhaps assuming people aren't using -Werror)? I don't think it can but perhaps generalizing the type could make type inference fail somewhere due to an ambiguous type.
We really need a PVP guide that just lists lots of examples, each with a note of what kind of change it is (i.e. major, minor, or patch).
On Mon, Dec 15, 2014 at 10:00 AM, Michael Snoyman
mailto:michael@snoyman.com> wrote: I'm a little bit uncertain of the PVP guidelines in a certain case[1], so I'd like to get some guidance/clarity. Suppose I have a library which provides the function:
myFunction :: IO () myFunction = forever $ putStrLn "Still here" >> threadDelay 10^6
Later, I realize (or someone points out to me) that I've over-specified the type signature, and really myFunction should be:
myFunction :: IO a
In this case, does the PVP specify that we should have a minor or a major version bump? I'm not certain if this counts as a breaking change or not.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

I've always understood the PVP to be meant to prevent (almost?) all
breakage, provided you follow the right relation between your imports
and dependency version ranges:
* If you depend on a range of minor versions (x.y.*), you should use
only qualified or explicit imports.
* If you depend on a range of bugfix versions (x.y.z.*), you can use
implicit imports.
That is why adding a function is a minor version bump, and not a
bugfix: it can break people using implicit imports.
In this case, theoretically you could break people's code, if it is
something like this:
f = myFunction >>= print
However, since the return type is (), I doubt anyone is doing this,
and I'd go for the pragmatic approach and make this change in a minor
(or even bugfix) version.
Erik
On Mon, Dec 15, 2014 at 6:10 PM, Roman Cheplyaka
Almost any API change can break existing code.
For example, adding a new function can break code.
I thought the guiding principle for PVP was how likely it is that a piece of client code will break, not if that's theoretically possible.
On 15/12/14 11:44, Johan Tibell wrote:
I think the question is: can this change cause existing code to stop compiling (perhaps assuming people aren't using -Werror)? I don't think it can but perhaps generalizing the type could make type inference fail somewhere due to an ambiguous type.
We really need a PVP guide that just lists lots of examples, each with a note of what kind of change it is (i.e. major, minor, or patch).
On Mon, Dec 15, 2014 at 10:00 AM, Michael Snoyman
mailto:michael@snoyman.com> wrote: I'm a little bit uncertain of the PVP guidelines in a certain case[1], so I'd like to get some guidance/clarity. Suppose I have a library which provides the function:
myFunction :: IO () myFunction = forever $ putStrLn "Still here" >> threadDelay 10^6
Later, I realize (or someone points out to me) that I've over-specified the type signature, and really myFunction should be:
myFunction :: IO a
In this case, does the PVP specify that we should have a minor or a major version bump? I'm not certain if this counts as a breaking change or not.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

2. Otherwise, if only new bindings, types, classes, non-orphan instances or modules (but see below) were added to the interface, then A.B may remain
Often a package maintainer wants to add to an API without breaking backwards compatibility, and in that case they can follow the rules of
1. 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 PVP is more specific than this and allows you to communicate how the
API changes and what downstream packages can depend on. From the PVP:
the same but the new C must be greater than the old C. Note that modifying
imports or depending on a newer version of another package may cause extra
non-orphan instances to be exported and thus force a minor version change.
So it's clear that adding a function requires a minor version bumps and
it's also what that means for downstream packages:
point 2, and increase only C. A client can specify that they are
insensitive to additions to the API by allowing a range of C values, e.g.
build-depends: base >= 2.1.1 && < 2.2.
("insensitive to additions to the API" links to
https://www.haskell.org/haskellwiki/Import_modules_properly.)
So yes, if you use open imports and allow new minor versions, your code
might break. This is expected.
What's not clear here is that this rule might a bit stricter than necessary:
the previous A.B. Note that modifying imports or depending on a newer
version of another package may cause extra orphan instances to be exported
and thus force a major version change.
According to this rule Michael's change requires a major version bump.
However, there might be backwards compatible type changes that could be
covered under rule 2 which are not. Whether Michael's change is such a type
change is what we're trying to figure out in this thread.
-- Johan
On Mon, Dec 15, 2014 at 6:10 PM, Roman Cheplyaka
Almost any API change can break existing code.
For example, adding a new function can break code.
I thought the guiding principle for PVP was how likely it is that a piece of client code will break, not if that's theoretically possible.
On 15/12/14 11:44, Johan Tibell wrote:
I think the question is: can this change cause existing code to stop compiling (perhaps assuming people aren't using -Werror)? I don't think it can but perhaps generalizing the type could make type inference fail somewhere due to an ambiguous type.
We really need a PVP guide that just lists lots of examples, each with a note of what kind of change it is (i.e. major, minor, or patch).
On Mon, Dec 15, 2014 at 10:00 AM, Michael Snoyman
mailto:michael@snoyman.com> wrote: I'm a little bit uncertain of the PVP guidelines in a certain case[1], so I'd like to get some guidance/clarity. Suppose I have a library which provides the function:
myFunction :: IO () myFunction = forever $ putStrLn "Still here" >> threadDelay 10^6
Later, I realize (or someone points out to me) that I've over-specified the type signature, and really myFunction should be:
myFunction :: IO a
In this case, does the PVP specify that we should have a minor or a major version bump? I'm not certain if this counts as a breaking change or not.

On 16/12/14 00:31, Johan Tibell wrote:
So yes, if you use open imports and allow new minor versions, your code might break. This is expected.
One similarly could argue that "if you use functions in polymorphic contexts and allow new minor versions, your code might break". This isn't in the PVP, but it's exactly in the same spirit, IMO. Roman

On Mon, Dec 15, 2014 at 11:39 PM, Roman Cheplyaka
On 16/12/14 00:31, Johan Tibell wrote:
So yes, if you use open imports and allow new minor versions, your code might break. This is expected.
One similarly could argue that "if you use functions in polymorphic contexts and allow new minor versions, your code might break".
This isn't in the PVP, but it's exactly in the same spirit, IMO.
I think this is a bad idea, since a "polymorphic context" (even if rigorously defined) is not clear from reading the code, you have to type check it in your head. The import style, on the other hand, is very simple to read and check if it matches the style of dependency version ranges. Erik

On 16/12/14 11:40, Erik Hesselink wrote:
On Mon, Dec 15, 2014 at 11:39 PM, Roman Cheplyaka
wrote: On 16/12/14 00:31, Johan Tibell wrote:
So yes, if you use open imports and allow new minor versions, your code might break. This is expected.
One similarly could argue that "if you use functions in polymorphic contexts and allow new minor versions, your code might break".
This isn't in the PVP, but it's exactly in the same spirit, IMO.
I think this is a bad idea, since a "polymorphic context" (even if rigorously defined) is not clear from reading the code, you have to type check it in your head. The import style, on the other hand, is very simple to read and check if it matches the style of dependency version ranges.
Ok, this is a fair point. Roman

I appreciate everyone's input on this. I've decided I'm going to treat this
as a minor version bump, for the following reasons:
* It's unclear that *any* breakage will occur.
* If any breakage does occur, it should be trivial to fix in a backwards
compatible way.
* And while breakage is generally a bad thing, in this case, it would
likely be beneficial to the community if we got extra data out of the
exercise by having a build breakage result from this change.
If I hear any reports of breakage as a result of this change, I'll try to
remember to report them.
On Tue Dec 16 2014 at 11:48:41 AM Roman Cheplyaka
On 16/12/14 11:40, Erik Hesselink wrote:
On Mon, Dec 15, 2014 at 11:39 PM, Roman Cheplyaka
wrote: On 16/12/14 00:31, Johan Tibell wrote:
So yes, if you use open imports and allow new minor versions, your code might break. This is expected.
One similarly could argue that "if you use functions in polymorphic contexts and allow new minor versions, your code might break".
This isn't in the PVP, but it's exactly in the same spirit, IMO.
I think this is a bad idea, since a "polymorphic context" (even if rigorously defined) is not clear from reading the code, you have to type check it in your head. The import style, on the other hand, is very simple to read and check if it matches the style of dependency version ranges.
Ok, this is a fair point.
Roman
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (7)
-
Adam Bergmark
-
Bardur Arantsson
-
Dan Burton
-
Erik Hesselink
-
Johan Tibell
-
Michael Snoyman
-
Roman Cheplyaka