ABI stands for application binary interface, and it represents how different precompiled components of a program interact. This can be a program calling out to an OS function or part of the language runtime, or even to a library if it’s dynamically linked.

In some languages, such as Swift, the standard library is ABI stable — that is, even source-breaking changes to the runtime or standard library must remain backwards-compatible with already-compiled programs. Additionally, programs compiled with a newer version of the compiler that don’t use new runtime components must continue to work with old versions of the runtime and standard library.

ABI stability causes challenges for language and library evolution. Some otherwise positively-received changes to Swift have been rejected since they can’t be implemented without breaking ABI. Other languages that aren’t ABI-stable don’t need to worry about this, and can change or remove existing features (though that may necessitate a major version bump).

With that background out of the way: When is ABI stability a net positive? What factors would cause a language to restrict itself in this way?


3 Answers 3


This is far from a comphrehensive answer but

When you need hot reloading

Some systems try to be always on. An upgrade requires that a new function or datastructure replaces another in place without the application being restarted or the rest of the code being recompiled. This could be signficantly harder without a stable ABI.

When your library is the target for other applications

Consider the C standard library and Posix. One is mandated by the language the other by the OS. However they overlap considerably.

You are not free to change the ABI for a compiler is it is mandated by the OS. If the OS ABI changes all packages on that OS may have to be recompiled.

The same reasoning applies if your language ecosystem includes a package manager which allows binary packages. They may break if the ABI changes and so will need to be re-compiled. To (re)compile packages from source requires your package manager to also be a compiler.

This is typically assuming ahead of time compilation.

When you don't want to break contracts

If the language is interpreted code may run but a change in the ABI might mean subtle a change in the contract so something may cease to comply with the contract introducing a subtle bug.

I haven't got a good real world example in mind off the top of my head but say you have a function

[requires: x < 100]
f(x: int) -> int

If you change that to:

[requires: x < 200]
f(x: int) -> int

In a new version of your API then a caller could legitimately think its okay to invoke f(101) but that call could go to an implementation using the old contract (x < 100) leading to undefined behaviour. This is a case where you should update the API version number (to indicate a breaking change) even though you might not be able to encode the contract in the interface itself.

Now consider the same logic applied to the case of an ABI instead of an API and replace the API pre-condition with an equivalent property of your ABI.

Say you pass a pointer and change who is responsibile for deleting the associated memory. The call may still appear to succeed but you will have a potenital resource leak.

  • $\begingroup$ Could you elaborate on that last one? If everything is distributed in source and either interpreted or JIT’ed, there’s not necessarily an ABI to speak of, is there? $\endgroup$
    – Bbrk24
    Commented Jun 21, 2023 at 18:16
  • $\begingroup$ I've tried to elaborate that in the answer. $\endgroup$ Commented Jun 21, 2023 at 20:43
  • 2
    $\begingroup$ That sounds more like API stability, which is different. Swift has a concept of "source-breaking ABI-stable changes", which I think that would fall under. $\endgroup$
    – Bbrk24
    Commented Jun 21, 2023 at 21:03
  • $\begingroup$ Maybe a better example for contract breaking would be when C# added non-nullable types, turning what was before a simple int to int?. $\endgroup$
    – kouta-kun
    Commented Jun 21, 2023 at 23:44
  • $\begingroup$ Yes indeed its not a good example. $\endgroup$ Commented Jun 22, 2023 at 1:01

It is actually very simple.

A stable ABI is needed when you need to link against libraries after compilation. If you have all the sources for your libs, you can just recompile it all with the new abi.

The problem is that there is no adult supervision in computing. As a result you often have to do this when it is actually unnecessary. Take the gamedev on linux example. The linux kernel syscalls don't change, ever. So you can build a static binary and never worry about linking. However, for graphics you are requiered to dynamically link against a userspace driver. This means the C abi must be stable for this to work.

Many "modern" languages require a precompiled runtime in addition to all the other garbage in order to run. This is a complete waste because those who wan't their software to actually run on someone else's machine bundle the runtime with their application. At which point there is no purpose for it to be a standalone binary!

If you are writing your own language there is no reason to have a stable abi unless you intend to distribute precompiled libraries.

I'm a believer that languages should be made finished and not modified, in which case your abi is stable because your language is stable.


Game development

Most of the time, games get little to no updates after a certain time passes. In desktop platforms, this can often mean that after some time they may not run at all. Linux games developed in the early 2000s for example have recently broken due to SDL updates, which is relatively easy to fix by replacing the original SDL. If the C standard library were to suffer breaking changes, this would be way harder to fix. Something similar did happen with glibc recently on an even deeper level, where they broke the mechanism used to find functions by name in libraries: https://lwn.net/Articles/904892/

  • 1
    $\begingroup$ I’ll point out that the C standard library did have a breaking change just this year, but afaict only in the uncommon case of realloc(ptr, 0). $\endgroup$
    – Bbrk24
    Commented Jun 20, 2023 at 18:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .