4

So I was learning about forward compatibility, and I was wondering if you could warn a "dependent" that a dependency is backward compatible, but not forward compatible*, and vice-versa.

The SemVer specification requires that:

7. Minor version Y (x.Y.z | x > 0) MUST be incremented if new, backwards compatible functionality [emphasis mine] is introduced to the public API. [...]

8. Major version X (X.y.z | X > 0) MUST be incremented if any backwards incompatible changes are introduced to the public API. It MAY include minor and patch level changes. [emphasis mine] [...]

To me, it means that:

  • You must increment the minor version when you do a backward compatible but not forward compatible* change. Indeed, if you introduced a "new [...] functionality [...] to the public API" and dependents upgrade the dependency and use it, the dependency can't guarantee that downgrading won't break any dependent, as a mirrored version of backward compatibility. So adding a "new [...] functionality [...] to the public API" is backward compatible and not forward compatible*, and I make the supposition that any backward compatible and not forward compatible* change is, in a way, adding "new [...] functionality [...] to the public API", because I don't see any counter-example (and other reasons I could explain if needed), making them basically equivalent.
  • You must increment the major version when you do a not backward compatible change. It can be forward compatible*, or not.
  • You must increment the patch version when you do a backward compatible and forward compatible* change, by elimination (and the same other reasons I could explain if needed).

Suppose that I'm right, and that any change that is both not backward compatible and not forward compatible* can be separated into two successive changes, one backward compatible and the other forward compatible* (or the other way around).
It would mean that you could always separate the not backward compatible but forward compatible* changes from the others, and never have a change that is both not backward compatible and not forward compatible*.
So you could redefine:

  • the major version as a forward compatible* version including at least one not backward compatible change
  • the minor version as a backward compatible version including at least one not forward compatible* change.

It would mean that any new major version M.0.p of a dependency can be downgraded safely by dependents, even until the last minor version of the preceding major version, let's call it (M-1).m.0.

Suppose that I'm right. Would it be beneficial or useless to the dependents to know that a version of a dependency is guaranteed to be forward compatible*?
What would be the pros and cons of that additional constraint to SemVer?

(verifying my reasoning is not the purpose of this question, I know that I'm overthinking, but I just want to know if this reasoning is useful in any way or not, however I would appreciate to have your opinion)


EDIT: Anywhere there is a "*" after "forward compatible", I meant "safely downgradable".
Indeed, when a version is backward compatible, it means that the previous version is safely upgradable. So when a version is forward compatible, it means that the next version is safely downgradable. It also means that you can't guarantee that a version is forward compatible before the next version is out. So you can guarantee that a new version is backward compatible or safely downgradable, but you can't guarantee that it's forward compatible or safely upgradable yet.

closed as too broad by gnat, BobDalgleish, Thomas Owens Mar 16 at 0:19

Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

4

Almost all changes are, by their very nature, forward incompatible:

  • If I fix a bug and release patch, then downgrading will introduce that bug.
  • If I introduce a new feature, then downgrading will remove that feature and so potentially leave the code in a non-compilable state.
  • If I make a breaking change, then that change will be breaking in either direction, eg I change Foo to Bar, then use Bar, I cannot then downgrade to the previous version.

As you say in your comment, the one exception to this is by using a minor change to introduce an alias and then a major change to remove the original and leave just the alias. In this specific situation, the major change is forward compatible.

So we could change 8 to:

Major version X (X.y.z | X > 0) MUST be incremented if any backwards incompatible changes are introduced to the public API. It MAY include minor and patch level changes. It MAY include forward compatible changes. Patch and minor version MUST be reset to 0 when major version is incremented.

But since we can only say "may" there, as forward compatibility is an edge case, what would this achieve other than to leave people confused and asking what that forward compatible clause was for?

  • I disagree with you: removing a public functionality, for example, is forward compatible: downgrading will just add it again, but the dependent won't use it. – CidTori Mar 13 at 10:35
  • Moreover, "substantial new functionality or improvements [...] introduced within the private code" (from SemVer) won't change the public API, so won't break anything. It would qualify as a patch within my version of SemVer. – CidTori Mar 13 at 10:39
  • Forward compatibility is just a mirrored version of backward compatibility, where you downgrade instead of upgrading, so if a backward compatible change is possible, a forward compatible change is too. – CidTori Mar 13 at 10:42
  • 2
    @CidTori, Regarding, "substantial new functionality or improvements [...] introduced within the private code". If its new functionality introduced purely within private code, then its not accessible via the API and thus is dead code that should never have been introduced in the first place. Substantial improvements must have an affect on the API, otherwise they aren't substantial improvements. For example, changes to the private code might halve the execution time of a function. Downgrading would then double that time, which could adversely affect my app. So that's not forward compatible. – David Arno Mar 13 at 10:52
  • 1
    @CidTori, "huge for the developper but transparent for the dependent" is not a justification for a change. If the API isn't changing in someway (even if its just for performance reasons), then don't inflict a new version on people as it brings no benefit. – David Arno Mar 13 at 11:02

Not the answer you're looking for? Browse other questions tagged or ask your own question.