C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Possible clean API break solution

From: Marcin Jaczewski <marcinjaczewski86_at_[hidden]>
Date: Thu, 1 Sep 2022 01:13:00 +0200
czw., 1 wrz 2022 o 00:41 Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]> napisał(a):
>
> On Wed, Aug 31, 2022 at 6:00 PM Marcin Jaczewski via Std-Proposals <std-proposals_at_[hidden]> wrote:
>>
>>
>> More a new version/flavor of C++, it could be in some way compared to the "epoch" proposal
>> but is more fine grained as you can specify each class for what version it belongs to.
>>
>> > > 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
>
>
> It seems like you're just reinventing "inline namespaces" — a feature which is already present in C++, and was added basically because people thought it might help with this kind of issue, but in fact it does not.

Yes, but the devil is in the details.

>
> namespace std {
> #ifdef OLD_ABI
> inline namespace older {
> struct string { int x, y; };
> }
> #else
> inline namespace newer {
> struct string { int y, x; };
> }
> #endif
> } // namespace std
>
> void myFunction(std::string x);
> // mangles as _Z10myFunctionNSt5older6stringE when defined(OLD_ABI)
> // mangles as _Z10myFunctionNSt5newer6stringE when !defined(OLD_ABI)
>
> One problem this doesn't solve is user-defined types.
>
> struct Name { std::string n; };
> void myFunction(Name x);
> // mangles as _Z10myFunction4Name no matter what ABI we're using
>

Basic idea from p2028r0 was that it will handle this case too. We do
not tweak some std types, we break everything, user types too.
in C++30 `myFunction` will mangle as `_Y10myFunction4Name` and will
not link with `_Z10myFunction4Name`.

What I propose is a way to avoid the python2 vs python3 community
split but still have the option for a clean API break.

In ONE cpp file you could write:
```
extern "C++20"
{
struct Name { std::string n; };
void myFunction(Name x);
// mangles as _Z10myFunction4Name
}

extern "C++30"
{
struct Name { std::string n; }; //this choose `std::_30::string`
void myFunction(Name x);
// mangles as _Y10myFunction4Name
}
```

I could say this is in some way "implicit global inline namespace" as
this nearly same behavior as:
```
inline namespace cpp20
{
struct Name { std::string n; };
void myFunction(Name x);
}
```
where the compiler adds `inline namespace cpp20` to every file during
compilation.

Aside from this it has a couple new mechanics to allow easier handling
of both versions at once.


> You go on to talk about programs that use both ABIs for std::string simultaneously — i.e., std::older::string and std::newer::string coexisting in the same program. That's generally not possible, or at least will cause problems. Recommended search terms: "semver", "diamond dependency".
> https://abseil.io/resources/swe-book/html/ch21.html
> Even if it were physically possible for two versions of std::string to coexist in your program, you wouldn't want that, because it would mean your program was twice as big as it ought to be.
>
> HTH,
> Arthur

There is not confusion between old and new, these are two separate
types with diffrent mangling and can live fine in the same exe.
Yes, this will increase binary size but this is the cost that user
want to pay for this. Because default behavior is to ignore all this
`extern` and recompile everything when the new standard hits.

Received on 2022-08-31 23:13:12