There's also this to look at on the subject: https://lkml.org/lkml/2018/8/3/621
Reddit discussion: https://www.reddit.com/r/linux/comments/95b1hf/linus_torvald...
You just can't break backwards compatibility.
This was a big mistake Python 3 made.
Think about it like totally new language
At least Python's backers had the guts to release a breaking version 3, unlike some other dynamic languages, specifically Ruby and Apache Groovy. Ruby's backers have tentatively slated 2020 for a (MRI) Ruby 3 release after two more Ruby 2.x versions. As for Groovy, 2 months ago its backers canceled its version 2.6 release which was to backport the planned features of Groovy 3 into a JDK 7 compatible release. Looks like we won't be seeing version 3 of either language anytime soon.
The backward-compatibility breaking Ruby release often held up as a parallel to Python 3—Ruby 1.9—was released December 25, 2007, about a year before Python 3.
If Python had as much guts as Ruby in this area we'd be seeing a backward-compatibility breaking Python 4 around 2021.
I remember attending JSF Days in 2009 and how we would be all writing Groovy JEE Beans in the near future, show in different ways across a few sessions, and here we are.
I don't suffer from XML allergy and am pretty fine with Maven in what concerns Maven projects.
Actually I was pretty happy with Eclipse + Ant + ndk-build as well.
To this day the NDK already went through a couple of Gradle build variations and it still doesn't support NDK libraries across NDK projects, as AAR only support binary libs for Java apps.
I follow Fuchsia with attention, but it might end up just as Brillo.
If you have to absolutely must break backwards compatibility. Break it once, and never again, in a way you fix your language permanently. Like Perl 6.
Python broke backwards compatibility for a print statement.
* Ruby had better dependency management. Python's only recently introduced Pipenv which provides a standard approach for managing development and prod dependencies. VirtualEnv's been around for a while but didn't handle scope.
* Ruby wasn't used as extensively as Python in stuff like system libs and start-up scripts so system packages weren't constrained in the same way.
* Ruby's ecosystem was more focused around web development. Rails in particular was fairly early in adopting new versions of Ruby within about 1 year of the release of Ruby 1.9. Django on the other hand was about 5 years before it had it's first Python 3 compatible release.
* "microbenchmarks" generally got better with Ruby releases whereas Python 3 seemed to have gotten worse from what I remember. I don't think microbenchmarks are terribly useful out of the context of an actual application but many people use them as indicators.
* subjectively I think the Ruby community was more committed to unit testing which made "fearless upgrades" a little more palatable.
Similarly, TeX shows the halmarks of stability. I can reliably rebuild any document I've ever written. However, that means that the styles I used to use to write documents have to still be supported. Contrast that with HTML, where they constantly give new methods to do something because they changed their mind about how it should be done. Worse, they no longer support the old ways, because they were supposedly "never supported."
I think there is some merit to change driving progress. It is just frustrating when so much change is effectively user hostile.
It's weird to me when people claim clojure is dying, yet the ecosystem is evolving rapidly and people are making money with it. It's not a model that's easy to starve, it's too lightweight to collapse under it's own load, and there's no way to kill it, so how is it dying?
Mindshare ebbs and flows, but being THE programming language was never clojure's goal.
During the release of 1.9 there were some issues relating to spec, libraries, and build tools in the pre-release versions. So I'm not sure I would say the rule is followed to the letter such that you can consume Alpha releases are safe. It was prerelease candidate so no biggie. I know there were some discussions on the mailing list of a formal security audit of the Clojure but I'm not sure where that went but I'd be interested in seeing the results.
That's also an argument for keeping security holes around. By definition those are bugs and users (albeit malicious ones) depend on them. How dare you fix a security hole and break a perfectly working exploit!
Now, there is a tradeoff between security and convenience. That is also why fraud techniques haven't taken away credit cards as a thing. To that end, sometimes it is better to engineer a detection/mitigation strategy instead of removing the convenience.
And life seems to be full of more strawmen then makes sense. So, yes, you can easily find examples for this in either direction.
It's something a lot of libraries could learn from. Most users want to build software for the long term and tend to avoid upgrading libraries too often.
Fwiw, this is a large part of Rich's Spec-ulation [0] talk.
I do think it can be very difficult to know if you, as a producer, are breaking any consumers. I'd love to see some sort of OSS build tool and CI system that automatically rebuilds and tests all consumers of your library to give you, the library author, more information about the changes you make before releasing.
Knowing a set of functions I rely on did not change (at all) provides more peace of mind to me than just knowing the function signature is still compatible.
Versioning (or at least understanding changes) on the function level in addition to the library level sounds so powerful to me that I wonder why this concept isn't more mainstream yet. Are there other examples?
[edit: I found codec: https://github.com/Datomic/codeq#codeq]
From the interview: “But there are really two very distinct kinds of change - there are breaking changes, where your expectations have been violated, and there are accretions, where there's just some more stuff where there wasn't stuff before. And in general, accretion is not breaking.”
To paraphrase stuff I’ve heard him talk about elsewhere, your library should never change a function to require more input or provide less output. If you decide to do that, call it something else and keep the old function around. He’s talked about function-level versioning too, touches on it here a bit. If I use library functions x y and z and the maintainers only broke (the contract for) functions a b and c, then I probably don’t care and can grab the latest version for its other new goodies. But that decision still requires me to read the library source or at least a changelog, even though it’s simple enough for the right tool to be able to report it to me. Spec looks like a step in that direction.
1. improving/providing secure defaults. 2. reducing the API surface so that usage is more evident. 3. refactoring that eases maintenance. 4. improving performance where appropriate. 5. probably others I haven't thought of.
In RFC style I would say it's a SHOULD rule rather than a MUST.
Using a concrete example relating to security; libressl maintained much of the API surface that OpenSSL provides. In essence they aimed to provide a "drop-in" replacement. However there were whole families of algorithms and functions which they deemed "unsafe/unfit" for purpose (e.g. FIPS algorithms). I think that's a perfectly valid exception to the rule. It acts as a canary in the coal mine and you have options; fix your code or defer upgrading.
I would advocate for thoughtful deprecation cycles over ossification of poor APIs and algorithms.