C++ Logo

std-proposals

Advanced search

[std-proposals] Possible clean API break solution

From: Marcin Jaczewski <marcinjaczewski86_at_[hidden]>
Date: Wed, 31 Aug 2022 01:44:27 +0200
I reread old paper about ABI stability and its cost:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2028r0.pdf

And I was wondering if it is possible to eat cake and still have it too?
Would it be possible to fix all small aggregate mistakes that happened
during years of standardization but not alienate all old code bases?

Would this be even possible? Or have historical precedents?
I think yes, even more I think whole C++ success was built on breakage
like this.
ABI break I am referring to is compatibility with C. C++ makes a break
from it by adding
mangling to allow linking safely with old C code without confusion.

Could we repeat breakage like this but this time inside C++?
p2028 suggests changing the mangling prefix to `_Y` and use of `extern
"C++20"` to
mark what old mangling should be used (similar how we use now `extern "C"`).

I could imagine that you could write code that could become version
invariant and
will work as long as the compiler supports old versions of standard.

```
extern "C++20" struct A
{
    std::_30::string x; //newer version of string for some improvements
    std::_20::vector<bool> y; //our favorite version of current vector :>
};

inline A Create(const std::string& x) //current `string` based on
compiler option
{
    return A{ x }; //implicit constructor from other version of `string`
}
```
And this code could be included in the header and work exactly
the same in all available versions of C++.
This means we could have forward and backward compatible ways to link code but
still have the option to break from time to time compatibility.

We could too hack old headers to make it supported in new compilation mode:
```
extern "C++20"
{

//this could be content of "MyType.h" header
#include <vector>

struct MyType
{
   std::vector<bool> v; //thanks to extern scope this work as `std::_20::vector`
};

//end of header
}

struct MyType //this is different `MyType` that have diffrent `std::vector`
{
    std::vector<bool> v;
};

//using MyTypeError = MyType; //error: name is ambiguous
using MyTypeOld = extern "C++20" MyType;
using MyTypeNew = extern "C++" MyType;

extern "C++20"
{
using MyTypeImplicit = MyType; // only see `extern "C++20" MyType`
using MyTypeExplicit = extern "C++" MyType; //but we can be explicit
what version we want
}
```

This will allow for big codebases to "freeze" some old parts to old
versions of C++ but still allow new compilers and new improvements in
other parts of code while still mixing both flavors.
cost of "freeze" of some headers will be same as writing C/C++ headers
that work for both languages:

```
#if __cplusplus > 202002L
extern "C++20" {
#endif

//...

#if __cplusplus > 202002L
} // extern "C++20"
#endif
```

Received on 2022-08-30 23:44:39