What programming language(s) satisfy this criteria, if any?
What programming language(s) satisfy this criteria, if any?
Thry do reserve the right to do breaking changes for security fixes, soundness fixes and inference changes (i.e. you may need to add an explicit type that was previously inferred but is now ambiguous). These are quite rare and usually quite small.
On the other hand, I did find what I think are the relevant docs [0] while looking more into things, so I got to learn something!
[0]: https://docs.adacore.com/gnat_rm-docs/html/gnat_rm/gnat_rm/c...
I can't think of any established language that doesn't fit that exact criteria.
The last major language breakage I'm aware of was either the .Net 2 to 3 or Python 2 to 3 changes (not sure which came first). Otherwise, pretty much every language that makes a break will make it in a small fashion that's well documented.
Java is very good here, but (and not totally it's fault) it did expose internal APIs to the userbase which have caused a decent amount of heartburn. If your old codebase has a route to `sun.misc.unsafe` then you'll have more of a headache making an upgrade.
Anyone that's been around for a while and dealt with the 8->9 transition has been bit here. 11->17 wasn't without a few hiccups. 17->21 and 21->25 have been uneventful.
PHP has had breaking changes [1].
Ruby has had breaking changes [2] (at the very least under "Compatibility issues")
Not entirely sure whether this counts, but ECMAScript has had breaking changes [3].
[0]: https://go.dev/blog/loopvar-preview
[1]: https://www.php.net/manual/en/migration80.incompatible.php
[2]: https://www.ruby-lang.org/en/news/2025/12/25/ruby-4-0-0-rele...
[3]: https://tc39.es/ecma262/2025/#sec-additions-and-changes-that...
*1: A great many examples of synthetic code were contrived to argue against the change, but none of them ever corresponded to Go code anyone would actually write organically, and an extensive period of investigation turned up nothing
*2: As in, the original behavior of the code was actually incorrect, but this wasn't discovered until after the loopvar change caused e.g. some tests to fail, prompting manual review of the relevant code; as a tangent, this raises the question of how often tests just conform to the code rather than the other way around
*: strongest competitor for "biggest noob trap" IMO is using defer in a loop/thinking defer is block scoped
C# for instance isn't such a "small language", it has grown, but code from older versions, that does not use the newer features will almost always compile and work as before.
breaking changes are for corner cases, e.g. https://github.com/dotnet/roslyn/blob/main/docs/compilers/CS...