I noticed this when recently writing a spec that defines backwards-compatibility. There's surprisingly few things you can do when you want to stay backwards-compatible.
With full backward compatibility, you agglomerate features, and changes are implemented as optional, with the default being the old behavior.
You can add layers that depend on existing code, but you cannot make existing code depend on those new layers.
/me runs ...
https://news.ycombinator.com/item?id=15602658
https://news.ycombinator.com/item?id=15593069
My comment was intended to be a wry one referencing those very interesting discussions and hinting that if you have types then you can more easily make breaking changes internally that aren't visible externally.
Who's "we"? I'm talking about changing the implementation.
> Did you watch the video segment?
I watched the bit where he said if you add a constructor to a sum type you have to change everywhere it's pattern matched. True. I'd love to see Clojure's solution where you don't have to change any existing code!
EDIT: Oh wait, I think it's even worse than that. I think he's talking about product types. In which case you should use projection functions and indeed you need to make no changes to old code!
1 - Not all changes can be kept internal, for example adding a new case to an ADT
2 - Internal changes can still alter the semantic of the API, even if from the outside everything still looks the same from the type system point of view
It is "possible" that my blowing my nose will disturb butterflies in China.
Internal to the organization that produces the software, they are highly meaningful. Extended to user base that reads the documentation, it remains equally meaningful.
Downstream that resists information and can not be controlled is on its own. Good luck.
There should be a mechanism for releasing breaking new major versions. And it is this:
1) Release a new version for all your DIRECT dependents. Ideally they should be subscribed to your updates.
2) After they have had ample time to test it, they will release an update for THEIR direct dependents.
At no time should C update A if C depends on B and B depends on A. In fact, ideally, if C depends on B1, ..., Bn then C will NOT upgrade A until all B's have upgraded. C should push the B's to do it and supply patches.
This means version pinning for all dependencies, my friends!!
The alternative is "dependency hell" or making multiple copies of A to live inside each B.
If some B's are taking their sweet time then it may be better for some C to submit a patch to B's repo, which even if not accepted can be pulled by other C's. The question is who "owns" or "maintains" a B project if they don't react to changes of some of their dependencies. The answer, I think, should be - fork the B if it's not being actively maintained.
Edit: I think HN needs a "reason for downvote" field, perhaps seen only by the person being downvoted. As it is, many downvotes convey very little useful information.
"Spec-ulation" - https://www.youtube.com/watch?v=oyLBGkS5ICk
Which I fully agree with, basically there are no major, minor, patch level changes, in reality every change is a possible breaking changes, because we don't control what downstream is doing with our software.