Hello,

My name is Mohamed Koubaa and I am a software developer that works on a large scale desktop application.  More than half of what I write is in C++ and I often think about physical layout and ABI.  I hope you'll consider my idea!  This is my first post  here and look forward to hearing feedback from all of you.

Reply-to: Mohamed Koubaa <koubaa.m at gmail ~dot~ com>

Introduction


This paper discusses a set of extensions to C++ to standardize a compatibility ABI in some parts of the standard library and type system.  It is not meant to propose an ABI for all types and language features


Motivation and Scope

C ABI compatibility is often wrongly assumed and expected by C++ developers.  The language evolution often will introduce new types and features leaving the ABI unspecified.  Over time, code begins to depend on this ABI and changes to it become infeasible or impossible. This situation is not inherently c++ic (using Herb’s term).  It is simply a historical outcome based on where the language came from and its often shared runtime with C.

ABI is not a problem with most other popular languages and is really holding back the C++ ecosystem.  The way other languages deal with (or don't have to) are:

  • C - Compatibility is a primary concern and the C ABI is practically how other languages often achieve ABI

  • Python - See above.  Python extension modules (often written using C++!) are ABI compatible because the CPython interface is, well, C.

  • JS/C#/Java - these languages use a virtual machine or interpreter so that the ABI design are outside of the domain of the everyday programmer and library author


After using C++ for some years I and others have the understanding that in order to have truly portable C++ code, it must be distributed as source code and built by clients.  Clients need to understand the (often varied) build systems and tests in order to use just about any useful C++ library.  This is a burden that is neither expected nor tolerated when using other compiled languages.


Another concern with the current state of affairs is that for any individual to be a competent software architect of large scale software systems (perhaps excluding distributed systems and microservices) needs to master the sharp edges around ABI compatibility.


One technique for building C++ code without dealing with ABI is called an hourglass pattern.  This means building a C layer at the interface of binaries and writing c++ code to wrap that C interface in a user friendly C++ API.  This is sometimes done using plain C and other times done using COM (on windows). Essentially, this is an admission that in order to have stable ABIs one must only use a small subset of C++ types and language features on the interface, and that subset is essentially C.   In the narrow center of the hourglass free functions for allocating and freeing memory, as well as errno() are often used and converted back into constructors, destructors and exceptions.


If a stable ABI is known which includes many important standard library types, language interop can become idiomatic.  For instance, a language consuming an exported method which returns a stable_vector can wrap that in the most appropriate language semantics.  I.e. IEnumerable/IList for C# or __len__ in python

Impact on the standard

This paper does *not* attempt to propose an ABI for the entirety of the c++ type system and library features.  Instead, a portion of the standard library (some existing, some new) will be marked as having a stable ABI, and library authors can opt into using that portion at the binary interface of libraries so that ABI compatibility is no longer a concern for their clients.  In spirit, this is no different than the hourglass pattern, except that the subset of C++ which can be considered to be ABI stable is larger than simply what is shared with C due to history. Examples of these types are the P0709 exception and ranges which are in c++20.  Examples of library features are a new stable_allocator and a std::stable metaclass which can be used for compile time reflection on classes to ensure that they are indeed stable.


Other language features are explicitly not expected to be stable and implementations of c++ can change their ABI at any time.  In practice it will likely be difficult for an implementation to do that until using stable ABIs at binary interfaces becomes a common practice.

Technical Specifications

This proposal introduces the notion of stable, a property of a type or feature whose ABI is defined to never change.  Stable can be thought of as a superset of is_standard_layout because ABI concerns extend beyond memory layout.  All types and language features are considered unstable unless explicitly defined as stable. Following are the list of all stable types and language features (there are not many):


  • Standard layout

  • P0709 exceptions

  • Stable_allocator

  • Fixed width integer types

  • Range

  • String_view

  • Array

  • Stable_vector

  • Stable_string


This set of types and features may grow slowly over time, much like constexpr did since c++11, except with less urgency and with no interest in someday covering the entire language.


std::stable_allocator

This proposal defines a std::stable_allocator which controls the behavior of the new and delete functions and fixes them to a given version of malloc() and free() on a given platform.  For instance, the windows platform has multiple C runtimes to choose from. Classes that have an allocator template argument and whose clients provide stable_allocator are such that any new and delete function that occurs in their member functions will use the stable allocator.  This will allow such a class to be allocated in one binary unit and deleted in another without worrying about the runtime of each unit.


std::stable metaclass

The std::stable metaclass can be used for types that which to declare themselves as ABI stable.  The class will fail to compile if any unstable types or features are used at the interface of such a class.

Modules

This proposal does not intend to provide any relationship between modules and the notion of stability.  Modules may include all language features which is larger in scope than stable ABI features. However, if a standard attribute is added for visible symbols/dll export (does this exist yet?), compilers may warn about any unstable types or features used in conjunction with that attribute.



Thanks,
Mohamed