I think there's more to be said wrt treating source-stability as a core Swift Evolution principle (not just, but also, as it applies to trailing closures in particular). I've spoken about holding breaking changes for a source-breaking release every few years here, but I would like to address two other aspects.
I assume that what prompted developers to ask you for source stability was primarily the period of subsequent Swift releases with numerous and wide-reaching source breaking changes. Some of those would iirc even change the behaviour of programs without failure to compile.
This was admittedly annoying and probably left a bad taste in many developers mouths, so I can understand wanting to tread lightly in this area. But I imagine a good bit of that ill will came from the relative suddenness and unexpectedness of these changes.
I also contend that except for very limited examples there is not really such thing as indefinite source stability even were we to keep Swift itself exactly as it is today, forever.
Now, one base assumption I'll make here is that to the developer, breaking language changes are not substantially different in their breaking-ness than breaking changes in APIs. I believe this should hold true with good enough error messaging and documentation.
With that in mind, APIs that programmers use in their applications get deprecated and eventually removed with updates of operating systems and libraries routinely. So if developers update their OS and dependencies, they will at some point have to change their source code to keep it in working order, even without changes to the language itself (should developers choose not to update OS and libraries, then they will probably also not update their compiler, so breaking language changes would not affect them).
Since API deprecations and removals are a widely employed tactic all over the industry (heck, even Java removes old, superseded APIs once in a while), I don't really see how a properly managed cycle of deprecation, then removal, of old APIs and syntax could not be adopted in Swift without angering or taxing developers too much.
Like I said in the post I linked above, I think Rusts editions are a good precedent, and I believe a strategy somewhat like the one I'll sketch out here would be beneficial in keeping Swift fresh, modern and cruft-free (especially for beginners that are learning Swift for the first time), while also being slow-paced and predictable enough to satisfy developers preferring slow-moving code-bases:
- We hold breaking changes for a new source-breaking language version that occurs every X (let's say 5) years
- The current compiler supports N language versions before the current one (maybe 2 or 3 which would mean 10 or 15 years of "source stability")
- ABI stability is not affected in any way, and modules using different versions can be used together
- We include warnings giving a very clear picture of the timeline of deprecation/removal of old language versions, so developers don't get surprised and have plenty of time to plan migrations
- With each new language version, we publish comprehensive documentation explaining all breaking changes that needed to be addressed to upgrade to the new version
Bonus points for providing as much automated migration as possible (for most changes I can imagine, such as the one being discussed here, that should be pretty feasible), or, where automatic migration is not possible, generating a list of source locations that need to be looked at by a human. The possibility to migrate a file at a time instead of a whole module at once would also be convenient.
Regarding the choice of X and N, I would believe three older versions and five years, so 15 years total (if you wrote your code just before a new language version is released, up to 20 in the luckiest case) to be ample time (N=2 would probably also do), but Rusts documentation commits to supporting all editions forever so just maybe that is also something that could be considered. While it certainly smells of introducing language dialects more than the case where old versions are eventually to be dropped, I would still prefer that over never ever fixing bad decisions at all.
One thing I haven't put much thought into, because I don't know the workings very well is how this would work with the textual representation of library interfaces (is that still a thing even?). This might throw a spanner here, but I hope/suspect that is something that could be made to work (and it also only affects a subset of syntax constructs anyway).
This is a huge wall of text so apologies for that, but I really would like for Swift to (eventually, even if it means waiting several years for changes) stay modern, without decades of cruft and "if only we could have"s, and—maybe most importantly—easy to learn (because, let's be real, where "actively harmful" begins, novice programmers have already been quite confused and frustrated by inconsistencies/weird quirks)
I also think it might be beneficial to set a precedent and get developers used to minor source-breakage every now and then for when we eventually find a thing that is considered actively harmful and requires a bigger source-break, lest we end up with a Python2/3 situation.
I guess I've said quite enough and will shut up about this topic now But please give this some more consideration before committing it to be a core Swift Evolution principle.