Well, that was possible since Swift 1.0, wasn't it? It is using Objective-C as a proper ABI just like Windows people use COM to mix and match different C and C++ versions.
Except that Apple doesn't provide proper dylib sharing (which doesn't really require an ABI in the first place, just versioning).
It wasn't possible until Swift 5 because of ABI stability. If we were to do that before Swift 5, we would still have to create binaries for each version of Xcode/iOS.
The ABI stability in the article is solely provided by ObjC, not by Swift. The "Swift ABI" of 5 only helps you with not having to embed the Swift libraries within the ObjC shielded module. (it "just" makes it smaller)
The point of the article is that you can use the stable ObjC ABI to wrap the Swift incompatibilities. And that was technically possible since Swift v1.
versioning does not solve anything -- just look at how many different versions of libraries are installed on systems that do "versioned" shared libraries.
Versioning a library makes it "easy" to break compatibility by allowing you to have an ever increasing number of copies of each library, but that comes at the cost of old software using old (potentially buggy and insecure) versions of libraries.
It also hurts performance as you're more likely to have to load multiple copies of almost identical libraries. That hits memory usage and launch time performance.
Finally having "versioned" libraries doesn't help if you have one application using libraries that have been built targeting different library versions. What does it mean if you have an API passing a struct/class/record around if different libraries have different ideas of what the in memory layout of that struct is?
OSX and iOS solve this by saying that the platform is ABI and API stable, and so something written and compiled 5 years ago still works today.
Windows does similar, the specific DLL hell problem that windows had was that they didn't make the compiler SDK part of the OS, so apps had to bring a copy of their particular SDK with them. Then they just copied them blindly into the win\system or whatever directory, because lazy programming (also a lot of apps had to ship copies of DLLs because windows didn't include basic behavior as part of the OS).
Linux does not handle this problem at all - it's considered a given that end users should expect to recompile apps after an update. Versioning the libraries just means you can maintain the string name of the library, rather than acknowledging that your unstable (in the api sense) is a different library.
Versioning solves the sole thing the "Swift 5 ABI" officially claims to solve: Avoiding to embed the Swift libraries in every single binary. If you have apps on your iPhone which use 3 different Swift versions, you would have 3 versioned copies of the runtime in any other environment. Instead those libraries are copied for _every single app_.
Windows is a prime example which uses versioning and still allows to share modules by the means of a proper ABI, COM (__stdcall and friends, yuck).
It is absolutely common to embed multiple C (yes, even C has no stable ABI on Windows!) and C++ runtimes in a single binary and use COM as the ABI.
Something like that would have worked for Swift as well, precisely as demonstrated by the article, using the simpler ObjC runtime as the ABI.
> What does it mean if you have an API passing a struct/class/record around if different libraries have different ideas of what the in memory layout of that struct is
That is precisely what an ABI declares and is used for. In the context of the post, the ABI is the _ObjC_ runtime, which is stable. That potentially different Swift versions being linked have different layouts doesn't matter.
The primary issue with Linux is that it doesn't have explicit support for two level namespaces within dynamic linking. Though it is again also not uncommon to mix ABI-unstable languages like C++ by the means of a stable ABI (either C or for example the ABI defined by Apache).
The title is slightly misleading, because Swift 5 does not have module stability, so the publicly facing code cannot use the Swift interface. It must use Objective-C (C should be valid too, but I don't think the attribute for this is public yet?)