Proposal for handling experimental features in libc++

Hi,

The way libc++ currently handles experimental features makes it difficult for vendors to ship those experimental features to their users with a good user experience. The main problems are:

- Experimental features are currently not opt-in, yet we remove them when they get standardized
- The standard in which an experimental feature is promoted to non-experimental usually doesn't match the standard the experimental feature was provided in, which creates a trap for users. For example, we removed <experimental/optional> (which was available in C++14) in favour of <optional> (available in C++17 only). Users that were using <experimental/optional> now need to BOTH upgrade to C++17, and start using <optional>.
- We currently still provide <experimental/*> headers after they've been removed, which is not super friendly for __has_include.

I'd like to request comments on the following plan for supporting experimental features going forward:

- We add a `-fexperimental` flag to Clang that libc++ can pick up. Experimental features are only enabled when that flag is passed. Note that we could also have Clang automatically link in `-lc++experimental` when `-fexperimental` is used.
- Experimental features are free to be available starting with whatever version of the Standard we want, since users are opting-in explicitly anyway.
- When we standardize an experimental feature, we keep the experimental feature around but we add a warning saying it will be removed in 2 LLVM releases.
- After 2 LLVM releases, we REMOVE the feature, meaning we remove the code associated to it (and the header too if there's nothing else in the header). We do not leave the header there with a warning or an error, as this is just confusing.

I think this is fairly simple and it should address all the problems I listed by simply forcing users to be explicit about what they want. I like adding a flag to Clang since it can handle linking in static libraries as needed, which is not currently possible.

One question that is still open with this proposal is the status of features that are part of an upcoming Standard, like <span>. Those features are not really "experimental" in the sense that they are in C++20, however they are experimental in the sense that we do reserve the right to change them until the Standard has shipped. I'm not sure whether those features should be considered experimental, or whether that status should apply only to TSes.

I'm signing up to do all the work entailed by this proposal.

Comments?
Louis

Hi,

The way libc++ currently handles experimental features makes it difficult for vendors to ship those experimental features to their users with a good user experience. The main problems are:

  • Experimental features are currently not opt-in, yet we remove them when they get standardized
  • The standard in which an experimental feature is promoted to non-experimental usually doesn’t match the standard the experimental feature was provided in, which creates a trap for users. For example, we removed <experimental/optional> (which was available in C++14) in favour of (available in C++17 only). Users that were using <experimental/optional> now need to BOTH upgrade to C++17, and start using .
  • We currently still provide <experimental/*> headers after they’ve been removed, which is not super friendly for __has_include.

I’d like to request comments on the following plan for supporting experimental features going forward:

  • We add a -fexperimental flag to Clang that libc++ can pick up. Experimental features are only enabled when that flag is passed. Note that we could also have Clang automatically link in -lc++experimental when -fexperimental is used.

The only problem that I see here is that people who are using experimental features will have to modify their build systems to pass -fexperimental.

  • Experimental features are free to be available starting with whatever version of the Standard we want, since users are opting-in explicitly anyway.

In general, I think that this is a bad idea; because the TSes are always based on some existing standard.
For example, the LFTS 2 was based on C++14, and LFTS 3 is based on C++17.
I don’t think we should mess with that w/o a compelling reason.

  • When we standardize an experimental feature, we keep the experimental feature around but we add a warning saying it will be removed in 2 LLVM releases.
  • After 2 LLVM releases, we REMOVE the feature, meaning we remove the code associated to it (and the header too if there’s nothing else in the header). We do not leave the header there with a warning or an error, as this is just confusing.

I think this is fairly simple and it should address all the problems I listed by simply forcing users to be explicit about what they want. I like adding a flag to Clang since it can handle linking in static libraries as needed, which is not currently possible.

One question that is still open with this proposal is the status of features that are part of an upcoming Standard, like . Those features are not really “experimental” in the sense that they are in C++20, however they are experimental in the sense that we do reserve the right to change them until the Standard has shipped. I’m not sure whether those features should be considered experimental, or whether that status should apply only to TSes.

We have a flag for those already. it’s named -std. The only way you get is to pass -std=c++2a. I don’t think we need another flag.

I’m signing up to do all the work entailed by this proposal.

Woo hoo! :wink:

– Marshall

Hi,

The way libc++ currently handles experimental features makes it difficult for vendors to ship those experimental features to their users with a good user experience. The main problems are:

  • Experimental features are currently not opt-in, yet we remove them when they get standardized
  • The standard in which an experimental feature is promoted to non-experimental usually doesn’t match the standard the experimental feature was provided in, which creates a trap for users. For example, we removed <experimental/optional> (which was available in C++14) in favour of (available in C++17 only). Users that were using <experimental/optional> now need to BOTH upgrade to C++17, and start using .
  • We currently still provide <experimental/*> headers after they’ve been removed, which is not super friendly for __has_include.

I’d like to request comments on the following plan for supporting experimental features going forward:

  • We add a -fexperimental flag to Clang that libc++ can pick up. Experimental features are only enabled when that flag is passed. Note that we could also have Clang automatically link in -lc++experimental when -fexperimental is used.

The only problem that I see here is that people who are using experimental features will have to modify their build systems to pass -fexperimental.

That seems acceptable, no? It makes it easier when those experimental features have a runtime (in which case you’ve already passed an extra argument).

  • Experimental features are free to be available starting with whatever version of the Standard we want, since users are opting-in explicitly anyway.

In general, I think that this is a bad idea; because the TSes are always based on some existing standard.
For example, the LFTS 2 was based on C++14, and LFTS 3 is based on C++17.
I don’t think we should mess with that w/o a compelling reason.

Are you saying that you’d rather have the experimental feature available on exactly the standard version it’s based on, and not the standard version it potentially targets?

  • When we standardize an experimental feature, we keep the experimental feature around but we add a warning saying it will be removed in 2 LLVM releases.
  • After 2 LLVM releases, we REMOVE the feature, meaning we remove the code associated to it (and the header too if there’s nothing else in the header). We do not leave the header there with a warning or an error, as this is just confusing.

I think this is fairly simple and it should address all the problems I listed by simply forcing users to be explicit about what they want. I like adding a flag to Clang since it can handle linking in static libraries as needed, which is not currently possible.

One question that is still open with this proposal is the status of features that are part of an upcoming Standard, like . Those features are not really “experimental” in the sense that they are in C++20, however they are experimental in the sense that we do reserve the right to change them until the Standard has shipped. I’m not sure whether those features should be considered experimental, or whether that status should apply only to TSes.

We have a flag for those already. it’s named -std. The only way you get is to pass -std=c++2a. I don’t think we need another flag.

That’s not quite right: https://godbolt.org/z/D2c_r1
I can get in C++17… It’s just empty! That ain’t great either, but I don’t think Louis is proposing to fix it at this point in time.

Hi,

The way libc++ currently handles experimental features makes it difficult for vendors to ship those experimental features to their users with a good user experience. The main problems are:

  • Experimental features are currently not opt-in, yet we remove them when they get standardized
  • The standard in which an experimental feature is promoted to non-experimental usually doesn’t match the standard the experimental feature was provided in, which creates a trap for users. For example, we removed <experimental/optional> (which was available in C++14) in favour of (available in C++17 only). Users that were using <experimental/optional> now need to BOTH upgrade to C++17, and start using .
  • We currently still provide <experimental/*> headers after they’ve been removed, which is not super friendly for __has_include.

I’d like to request comments on the following plan for supporting experimental features going forward:

  • We add a -fexperimental flag to Clang that libc++ can pick up. Experimental features are only enabled when that flag is passed. Note that we could also have Clang automatically link in -lc++experimental when -fexperimental is used.

The only problem that I see here is that people who are using experimental features will have to modify their build systems to pass -fexperimental.

That seems acceptable, no? It makes it easier when those experimental features have a runtime (in which case you’ve already passed an extra argument).

  • Experimental features are free to be available starting with whatever version of the Standard we want, since users are opting-in explicitly anyway

In general, I think that this is a bad idea; because the TSes are always based on some existing standard.
For example, the LFTS 2 was based on C++14, and LFTS 3 is based on C++17.
I don’t think we should mess with that w/o a compelling reason.

Are you saying that you’d rather have the experimental feature available on exactly the standard version it’s based on, and not the standard version it potentially targets?

I’m saying I don’t want to have experimental features available on an earlier standard than what they’re targeting (absent a VERY good reason).

  • When we standardize an experimental feature, we keep the experimental feature around but we add a warning saying it will be removed in 2 LLVM releases.
  • After 2 LLVM releases, we REMOVE the feature, meaning we remove the code associated to it (and the header too if there’s nothing else in the header). We do not leave the header there with a warning or an error, as this is just confusing.

I think this is fairly simple and it should address all the problems I listed by simply forcing users to be explicit about what they want. I like adding a flag to Clang since it can handle linking in static libraries as needed, which is not currently possible.

One question that is still open with this proposal is the status of features that are part of an upcoming Standard, like . Those features are not really “experimental” in the sense that they are in C++20, however they are experimental in the sense that we do reserve the right to change them until the Standard has shipped. I’m not sure whether those features should be considered experimental, or whether that status should apply only to TSes.

We have a flag for those already. it’s named -std. The only way you get is to pass -std=c++2a. I don’t think we need another flag.

That’s not quite right: https://godbolt.org/z/D2c_r1
I can get in C++17… It’s just empty! That ain’t great either, but I don’t think Louis is proposing to fix it at this point in time.

You get the span header, yes - but not std::span
I’m pretty sure that you (Apple) are not interested in shipping six different sets of headers - one each for 98/03/11/14/17/2a

– Marshall

Hi,

The way libc++ currently handles experimental features makes it difficult for vendors to ship those experimental features to their users with a good user experience. The main problems are:

  • Experimental features are currently not opt-in, yet we remove them when they get standardized
  • The standard in which an experimental feature is promoted to non-experimental usually doesn’t match the standard the experimental feature was provided in, which creates a trap for users. For example, we removed <experimental/optional> (which was available in C++14) in favour of (available in C++17 only). Users that were using <experimental/optional> now need to BOTH upgrade to C++17, and start using .
  • We currently still provide <experimental/*> headers after they’ve been removed, which is not super friendly for __has_include.

I’d like to request comments on the following plan for supporting experimental features going forward:

  • We add a -fexperimental flag to Clang that libc++ can pick up. Experimental features are only enabled when that flag is passed. Note that we could also have Clang automatically link in -lc++experimental when -fexperimental is used.

The only problem that I see here is that people who are using experimental features will have to modify their build systems to pass -fexperimental.

That seems acceptable, no? It makes it easier when those experimental features have a runtime (in which case you’ve already passed an extra argument).

  • Experimental features are free to be available starting with whatever version of the Standard we want, since users are opting-in explicitly anyway

In general, I think that this is a bad idea; because the TSes are always based on some existing standard.
For example, the LFTS 2 was based on C++14, and LFTS 3 is based on C++17.
I don’t think we should mess with that w/o a compelling reason.

Are you saying that you’d rather have the experimental feature available on exactly the standard version it’s based on, and not the standard version it potentially targets?

I’m saying I don’t want to have experimental features available on an earlier standard than what they’re targeting (absent a VERY good reason).

Should something like optional only have targeted 17 then? Since that’s what it targeted (versus base standard). I’m not sure I like one versus another, but I’d like to understand your positioning and reasoning. Basically, I have no idea what our policy should be here and would like to hear arguments for one direction versus another.

From what I can tell, it’s useful for new experiments features to work with old standards: we’ll get more input from more people because it’s easier to use. However, that ease means it’s harder to get rid of experiments later! The later is what Louis is worried about: we’ve found it hard with our own users. At the same time, the committee doesn’t know when something will actually ship (i.e. LFTS doesn’t really target a particular standard for release, just as a base).

So I have no idea what the best policy is.

  • When we standardize an experimental feature, we keep the experimental feature around but we add a warning saying it will be removed in 2 LLVM releases.
  • After 2 LLVM releases, we REMOVE the feature, meaning we remove the code associated to it (and the header too if there’s nothing else in the header). We do not leave the header there with a warning or an error, as this is just confusing.

I think this is fairly simple and it should address all the problems I listed by simply forcing users to be explicit about what they want. I like adding a flag to Clang since it can handle linking in static libraries as needed, which is not currently possible.

One question that is still open with this proposal is the status of features that are part of an upcoming Standard, like . Those features are not really “experimental” in the sense that they are in C++20, however they are experimental in the sense that we do reserve the right to change them until the Standard has shipped. I’m not sure whether those features should be considered experimental, or whether that status should apply only to TSes.

We have a flag for those already. it’s named -std. The only way you get is to pass -std=c++2a. I don’t think we need another flag.

That’s not quite right: https://godbolt.org/z/D2c_r1
I can get in C++17… It’s just empty! That ain’t great either, but I don’t think Louis is proposing to fix it at this point in time.

You get the span header, yes - but not std::span
I’m pretty sure that you (Apple) are not interested in shipping six different sets of headers - one each for 98/03/11/14/17/2a

Not for this proposal… but it is unfortunate that we have empty headers. We can rejigger things through search path without shipping multiple headers.

Hi,

The way libc++ currently handles experimental features makes it difficult for vendors to ship those experimental features to their users with a good user experience. The main problems are:

  • Experimental features are currently not opt-in, yet we remove them when they get standardized
  • The standard in which an experimental feature is promoted to non-experimental usually doesn’t match the standard the experimental feature was provided in, which creates a trap for users. For example, we removed <experimental/optional> (which was available in C++14) in favour of (available in C++17 only). Users that were using <experimental/optional> now need to BOTH upgrade to C++17, and start using .
  • We currently still provide <experimental/*> headers after they’ve been removed, which is not super friendly for __has_include.

I’d like to request comments on the following plan for supporting experimental features going forward:

  • We add a -fexperimental flag to Clang that libc++ can pick up. Experimental features are only enabled when that flag is passed. Note that we could also have Clang automatically link in -lc++experimental when -fexperimental is used.

The only problem that I see here is that people who are using experimental features will have to modify their build systems to pass -fexperimental.

That seems acceptable, no? It makes it easier when those experimental features have a runtime (in which case you’ve already passed an extra argument).

  • Experimental features are free to be available starting with whatever version of the Standard we want, since users are opting-in explicitly anyway

In general, I think that this is a bad idea; because the TSes are always based on some existing standard.
For example, the LFTS 2 was based on C++14, and LFTS 3 is based on C++17.
I don’t think we should mess with that w/o a compelling reason.

Are you saying that you’d rather have the experimental feature available on exactly the standard version it’s based on, and not the standard version it potentially targets?

I’m saying I don’t want to have experimental features available on an earlier standard than what they’re targeting (absent a VERY good reason).

Should something like optional only have targeted 17 then? Since that’s what it targeted (versus base standard). I’m not sure I like one versus another, but I’d like to understand your positioning and reasoning. Basically, I have no idea what our policy should be here and would like to hear arguments for one direction versus another.

You’re going to have to be more precise here.

std::experimental::optional was a LFTS 2 thing. That TS was based on C++14. It was available in libc++ when the user specified C++14 (or later).
[N.B. std::experimental::optional has been removed from libc++ ]

std::optional is a C++17 thing. It is available in libc++ when the user specifies C++17 (or later).

From what I can tell, it’s useful for new experiments features to work with old standards: we’ll get more input from more people because it’s easier to use. However, that ease means it’s harder to get rid of experiments later! The later is what Louis is worried about: we’ve found it hard with our own users. At the same time, the committee doesn’t know when something will actually ship (i.e. LFTS doesn’t really target a particular standard for release, just as a base).

So I have no idea what the best policy is.

Many of the new TS features build upon features in the base language; which makes supporting them for older standards … harder.
(Not all of them, of course)

– Marshall

Hi,

The way libc++ currently handles experimental features makes it difficult for vendors to ship those experimental features to their users with a good user experience. The main problems are:

  • Experimental features are currently not opt-in, yet we remove them when they get standardized
  • The standard in which an experimental feature is promoted to non-experimental usually doesn’t match the standard the experimental feature was provided in, which creates a trap for users. For example, we removed <experimental/optional> (which was available in C++14) in favour of (available in C++17 only). Users that were using <experimental/optional> now need to BOTH upgrade to C++17, and start using .
  • We currently still provide <experimental/*> headers after they’ve been removed, which is not super friendly for __has_include.

I’d like to request comments on the following plan for supporting experimental features going forward:

  • We add a -fexperimental flag to Clang that libc++ can pick up. Experimental features are only enabled when that flag is passed. Note that we could also have Clang automatically link in -lc++experimental when -fexperimental is used.

The only problem that I see here is that people who are using experimental features will have to modify their build systems to pass -fexperimental.

That seems acceptable, no? It makes it easier when those experimental features have a runtime (in which case you’ve already passed an extra argument).

  • Experimental features are free to be available starting with whatever version of the Standard we want, since users are opting-in explicitly anyway

In general, I think that this is a bad idea; because the TSes are always based on some existing standard.
For example, the LFTS 2 was based on C++14, and LFTS 3 is based on C++17.
I don’t think we should mess with that w/o a compelling reason.

Are you saying that you’d rather have the experimental feature available on exactly the standard version it’s based on, and not the standard version it potentially targets?

I’m saying I don’t want to have experimental features available on an earlier standard than what they’re targeting (absent a VERY good reason).

Should something like optional only have targeted 17 then? Since that’s what it targeted (versus base standard). I’m not sure I like one versus another, but I’d like to understand your positioning and reasoning. Basically, I have no idea what our policy should be here and would like to hear arguments for one direction versus another.

You’re going to have to be more precise here.

std::experimental::optional was a LFTS 2 thing. That TS was based on C++14. It was available in libc++ when the user specified C++14 (or later).
[N.B. std::experimental::optional has been removed from libc++ ]

std::optional is a C++17 thing. It is available in libc++ when the user specifies C++17 (or later).

Okay, so essentially what you’re saying is that experimental features should always be available starting with the standard they’re based on, not a potential standard they might end up shipping in (when taken out of the TS)? That clearly makes sense and it’s a valid point of view.

Another point of view is that of users that don’t really know anything about TSes and when things land in a Standard. From their perspective, std::experimental::optional is the same thing as std::optional, just not “experimental”. They don’t see those as two completely different types. With that point of view, they expect that if they’re using std::experimental::optional in C++14, then they should be able to use std::optional in C++14 too, and they’re surprised when they realize they need to move to C++17.

I understand both points of view, however I think the second one serves our users best because, like I said, they don’t know about TSes and they don’t (nor should they) understand the standardization process. That being said, I’d be fine with adopting the first point of view (i.e. that std::experimental::optional should be available starting with C++14 but std::optional only with C++17), at least for now. At least, if users are required to opt-in explicitly, I think this makes everything much easier.

Louis

Hi,

The way libc++ currently handles experimental features makes it difficult for vendors to ship those experimental features to their users with a good user experience. The main problems are:

  • Experimental features are currently not opt-in, yet we remove them when they get standardized
  • The standard in which an experimental feature is promoted to non-experimental usually doesn’t match the standard the experimental feature was provided in, which creates a trap for users. For example, we removed <experimental/optional> (which was available in C++14) in favour of (available in C++17 only). Users that were using <experimental/optional> now need to BOTH upgrade to C++17, and start using .
  • We currently still provide <experimental/*> headers after they’ve been removed, which is not super friendly for __has_include.

I’d like to request comments on the following plan for supporting experimental features going forward:

  • We add a -fexperimental flag to Clang that libc++ can pick up. Experimental features are only enabled when that flag is passed. Note that we could also have Clang automatically link in -lc++experimental when -fexperimental is used.

The only problem that I see here is that people who are using experimental features will have to modify their build systems to pass -fexperimental.

That seems acceptable, no? It makes it easier when those experimental features have a runtime (in which case you’ve already passed an extra argument).

  • Experimental features are free to be available starting with whatever version of the Standard we want, since users are opting-in explicitly anyway

In general, I think that this is a bad idea; because the TSes are always based on some existing standard.
For example, the LFTS 2 was based on C++14, and LFTS 3 is based on C++17.
I don’t think we should mess with that w/o a compelling reason.

Are you saying that you’d rather have the experimental feature available on exactly the standard version it’s based on, and not the standard version it potentially targets?

I’m saying I don’t want to have experimental features available on an earlier standard than what they’re targeting (absent a VERY good reason).

Should something like optional only have targeted 17 then? Since that’s what it targeted (versus base standard). I’m not sure I like one versus another, but I’d like to understand your positioning and reasoning. Basically, I have no idea what our policy should be here and would like to hear arguments for one direction versus another.

You’re going to have to be more precise here.

std::experimental::optional was a LFTS 2 thing. That TS was based on C++14. It was available in libc++ when the user specified C++14 (or later).
[N.B. std::experimental::optional has been removed from libc++ ]

std::optional is a C++17 thing. It is available in libc++ when the user specifies C++17 (or later).

Okay, so essentially what you’re saying is that experimental features should always be available starting with the standard they’re based on, not a potential standard they might end up shipping in (when taken out of the TS)? That clearly makes sense and it’s a valid point of view.

Yes.

Another point of view is that of users that don’t really know anything about TSes and when things land in a Standard. From their perspective, std::experimental::optional is the same thing as std::optional, just not “experimental”.

We’re not in control of their ignorance.

They’re not the same, and they’re never going to be the same.
(Even if we didn’t remove std::experimental::optional, they still would not be the same)

They don’t see those as two completely different types. With that point of view, they expect that if they’re using std::experimental::optional in C++14, then they should be able to use std::optional in C++14 too, and they’re surprised when they realize they need to move to C++17.

Then they will be surprised.
They will have to learn what the difference between std::optional and std::experimental::optional is (along with the differences between the two)

I understand both points of view, however I think the second one serves our users best because, like I said, they don’t know about TSes and they don’t (nor should they) understand the standardization process.

Then they should avoid everything in std::experimental.
There’s a reason it was named that. Things there are EXPERIMENTAL. As in, NOT STANDARD.

I’m coming into this conversation late, so let me pontificate for a moment:

A large problem for the C++ commitee and standardization in general is that we don’t actually get feedback from
the experimental components we standardize and which standard libraries ship.

We want user feedback. And user feedback only comes when vendors can ship these experiments to users.

The utility of feedback is it allows us to fix the experimental specification before it becomes locked in. This means
allowing experimental implementation to change and evolve. We need to be allowed to make breaking changes.
This requires breaking users.

With that in mind, here are my thoughts on the proposal:

  • The “experimental” treatment should apply only to components the ISO C++ committee deams “experimental”.

  • std::experimental::foo and std::foo are different things. It’s important for users to understand that
    std::experimental::foo provides none of the same API/ABI stability guarantees std::foo does.

  • We want to make it easy for users to transition from std::experimental::foo to std::foo.

  • It’s super surprising when std::experimental::foo and std::foo both exist but have different behavior. If
    the std:: version changed, we should consider this a bug fix against the experimental specification. Having
    two disparate sets of behavior helps no one.

libc++ should be hyper-sensitive to the needs of vendors like Apple here. Otherwise our experimental
components find no audience.

Thanks for working on this Louis

/Eric

I’m coming into this conversation late, so let me pontificate for a moment:

A large problem for the C++ commitee and standardization in general is that we don’t actually get feedback from
the experimental components we standardize and which standard libraries ship.

We want user feedback. And user feedback only comes when vendors can ship these experiments to users.

Right.

The utility of feedback is it allows us to fix the experimental specification before it becomes locked in. This means
allowing experimental implementation to change and evolve. We need to be allowed to make breaking changes.
This requires breaking users.

Agreed.

With that in mind, here are my thoughts on the proposal:

  • The “experimental” treatment should apply only to components the ISO C++ committee deems “experimental”.

  • std::experimental::foo and std::foo are different things. It’s important for users to understand that
    std::experimental::foo provides none of the same API/ABI stability guarantees std::foo does.

Right.

  • We want to make it easy for users to transition from std::experimental::foo to std::foo.

I don’t see how we (libc++) have any affect on this; other than making sure that std::foo is available.

  • It’s super surprising when std::experimental::foo and std::foo both exist but have different behavior. If

the std:: version changed, we should consider this a bug fix against the experimental specification. Having
two disparate sets of behavior helps no one.

I disagree here; each one has a different specification.
We should match the specs. If someone wants the new behavior in std::foo, then they should use std::foo.

In the long (or even not-so-long) run, there should be only one: std::foo.
Once that has landed in a shipping standard, we should get rid of std::experimental::foo as soon as possible.

– Marshall

I think that Eric is saying is: people use std::experimental::optional because they want optional, whatever that is. They don’t really understand what “experimental" means. When they try to migrate to the standard version, it is surprising that stuff changes, or that they have to upgrade to C++17.

I agree that they’re using “experimental” wrong if that’s their expectation… but it is their expectation nonetheless! And it now looks like we’ve pushed churn onto them. What Louis is trying to do is make “experimental”’s meaning more obvious, while also giving users more runway for deprecation (so they can upgrade at their leisure). It’ll make it less frustrating for people who use experimental stuff. That’s desirable because we want their feedback! If we burn them with experiments they won’t want to try out our experiments, and we’ll be poorer for it.

I’m coming into this conversation late, so let me pontificate for a moment:

[snip]

With that in mind, here are my thoughts on the proposal:

  • std::experimental::foo and std::foo are different things. It’s important for users to understand that
    std::experimental::foo provides none of the same API/ABI stability guarantees std::foo does.

Not only that, but there is no guarantee that std::experimental::foo and std::foo behave the same.
(Similar, almost certainly yes - but in detail, probably not)
Optional is the poster child here.

If people want stability, guarantees against breaking changes, etc. - then they should not use stuff in std::experimental.
Period. Full stop.
Wait for it to appear in a standard.

– Marshall

Okay, so I had a discussion with Marshall last Friday, and I’d like to summarize the current situation and where we disagree. Marshall, please feel free to amend anything I say below.

My main gripe is that the user experience for experimental features is currently not excellent. In particular, users are making assumptions they shouldn’t make about experimental features, and they end up using those features in places where an experimental feature wouldn’t belong (e.g. an API boundary of a stable library, or somewhere that requires ABI stability). This ends up biting them (and hence us too) when we break those assumptions. Note that I fully understand this is a “users are misbehaving” kind of problem. However, I think it is unrealistic to expect users to know about TSes, Standard release cycles, and even important things like ABI stability. I think we must put mechanisms in place to force them to behave correctly.

More specifically, I’m trying to address the problem on three main fronts:

  1. I want users to opt-in explicitly and at the compiler flag level to get experimental features. Otherwise, the declarations are not present in the headers. This way, by default, they don’t have access to experimental features. If they want them, they must enable the flag in their project (and all dependent projects in case of a library), which I claim is going to make them understand the experimental nature of those features.
  2. I want to have a user-friendly way of using non header-only experimental features. This is a nice-to-have.
  3. I want to have a user-visible way of warning users that an experimental feature is going to be removed in a few LLVM releases. People don’t read the documentation and they don’t follow exactly when we implement the non experimental version of a feature.

Marshall’s opinion is that adding barriers to use experimental features is just going to be frustrating and will not change the fact that users make incorrect assumptions about experimental features. We already put those features in a experimental namespace, and users are just going to add the compiler flag without really considering the implications.

So we disagree on (1), specifically the part where -fexperimental would control whether we provide the declarations of experimental features in libc++. However, we both agree on (2) and (3), although we don’t agree on how to solve (3) exactly – but I don’t think that’s the main point of contention. I see a couple of paths we can take going forward:

  1. Status quo, which leads to embarrassing situations where we break users and tell them “it’s your problem, the feature was experimental”.
  2. We adopt my proposal as-is.
  3. We adopt my proposal but we don’t add -fexperimental (or we add it but it only controls whether -lc++experimental is linked). It is an improvement over the status quo because we still agree to add deprecation warnings when we ship the non-experimental version of a feature.

Any thoughts?
Louis

I’m coming into this conversation late, so let me pontificate for a moment:

[snip]

With that in mind, here are my thoughts on the proposal:

  • std::experimental::foo and std::foo are different things. It’s important for users to understand that
    std::experimental::foo provides none of the same API/ABI stability guarantees std::foo does.

Not only that, but there is no guarantee that std::experimental::foo and std::foo behave the same.
(Similar, almost certainly yes - but in detail, probably not)
Optional is the poster child here.

If people want stability, guarantees against breaking changes, etc. - then they should not use stuff in std::experimental.
Period. Full stop.
Wait for it to appear in a standard.

Okay, so I had a discussion with Marshall last Friday, and I’d like to summarize the current situation and where we disagree. Marshall, please feel free to amend anything I say below.

My main gripe is that the user experience for experimental features is currently not excellent. In particular, users are making assumptions they shouldn’t make about experimental features, and they end up using those features in places where an experimental feature wouldn’t belong (e.g. an API boundary of a stable library, or somewhere that requires ABI stability). This ends up biting them (and hence us too) when we break those assumptions. Note that I fully understand this is a “users are misbehaving” kind of problem. However, I think it is unrealistic to expect users to know about TSes, Standard release cycles, and even important things like ABI stability. I think we must put mechanisms in place to force them to behave correctly.

More specifically, I’m trying to address the problem on three main fronts:

  1. I want users to opt-in explicitly and at the compiler flag level to get experimental features. Otherwise, the declarations are not present in the headers. This way, by default, they don’t have access to experimental features. If they want them, they must enable the flag in their project (and all dependent projects in case of a library), which I claim is going to make them understand the experimental nature of those features.

If this is what Apple needs in order to provide these features to their users, then I support it. What is most important to me is getting these features in the hands of users.
I hear Marshall’s concern, and adding additional barriers will cause problems for some users. For example, ones using Clang before -fexperimental was implemented.

My opinion is that typing <experimental/foo> or std::experimental::foo should be enough to communicate the true experimental nature of these components to users.
Speaking to other STL implementers/vendors, they seem to share this position. But I don’t feel so strongly that I want to block progress on this issue.

That being said, let me proposal an middle ground: Let’s add a compiler warning.

The compiler warning would diagnose any use of std::experimental names. It would produce a good quality diagnostic about how the use of experimental components
should be explicitly opted into because they are not ABI or API stable, and that users who understand these risks can disable the warning in this way (Perhaps by specifying
-fexperimental).

With a warning the diagnostic the user hits when first trying to use std::experimental::foo will be a lot more understandable than if the identifier simply isn’t present.

And it would provide better compatibility with older Clang versions or GCC. The warning approach would have consistent behavior across standard library implementations.

Apple can ship the warning as on-by-default making the use of experimental components explicitly opt-in.

The warning also leaves open the -fexperimental path if we choose to go down it.

Thoughts?

I’m coming into this conversation late, so let me pontificate for a moment:

[snip]

With that in mind, here are my thoughts on the proposal:

  • std::experimental::foo and std::foo are different things. It’s important for users to understand that
    std::experimental::foo provides none of the same API/ABI stability guarantees std::foo does.

Not only that, but there is no guarantee that std::experimental::foo and std::foo behave the same.
(Similar, almost certainly yes - but in detail, probably not)
Optional is the poster child here.

If people want stability, guarantees against breaking changes, etc. - then they should not use stuff in std::experimental.
Period. Full stop.
Wait for it to appear in a standard.

Okay, so I had a discussion with Marshall last Friday, and I’d like to summarize the current situation and where we disagree. Marshall, please feel free to amend anything I say below.

Thanks for summarizing.
Will do :slight_smile:

My main gripe is that the user experience for experimental features is currently not excellent.

Agreed.

In particular, users are making assumptions they shouldn’t make about experimental features, and they end up using those features in places where an experimental feature wouldn’t belong (e.g. an API boundary of a stable library, or somewhere that requires ABI stability). This ends up biting them (and hence us too) when we break those assumptions. Note that I fully understand this is a “users are misbehaving” kind of problem. However, I think it is unrealistic to expect users to know about TSes, Standard release cycles, and even important things like ABI stability. I think we must put mechanisms in place to force them to behave correctly.

I disagree here. These are professional software developers; who are making their livelihood producing software.
Expecting them to be informed is not unreasonable.

More specifically, I’m trying to address the problem on three main fronts:

  1. I want users to opt-in explicitly and at the compiler flag level to get experimental features. Otherwise, the declarations are not present in the headers. This way, by default, they don’t have access to experimental features. If they want them, they must enable the flag in their project (and all dependent projects in case of a library), which I claim is going to make them understand the experimental nature of those features.

I believe that referencing the experimental namespace is just as significant an opt-in.

  1. I want to have a user-friendly way of using non header-only experimental features. This is a nice-to-have.

Agreed. This would be nice. As I’ve said before, I’m fine with adding -fexperimental as a syonym for -lc++experimental.

  1. I want to have a user-visible way of warning users that an experimental feature is going to be removed in a few LLVM releases. People don’t read the documentation and they don’t follow exactly when we implement the non experimental version of a feature.

I’m fine with this, but I believe (strongly) that the build system is not the correct place for this.

To someone trying to get a release out (this week!) a warning on each build that “this feature is going away in a year” is just noise, and gets in the way of finding actual problems with the build.

I think that cramming stuff like this into the build system is a manifestation of “when you have a hammer, everything looks like a nail”.

Marshall’s opinion is that adding barriers to use experimental features is just going to be frustrating and will not change the fact that users make incorrect assumptions about experimental features. We already put those features in a experimental namespace, and users are just going to add the compiler flag without really considering the implications.

Yes.

If you believe that adding #include <experimental/optional> (say) is done w/o considering the implications, why do you believe that adding -fexperimental to a make file will not be done in a similar manner?

I refer you to the seminal work “Copying and Pasting from Stack Overflow” (https://www.goodreads.com/book/show/29437996-copying-and-pasting-from-stack-overflow) :slight_smile:

So we disagree on (1), specifically the part where -fexperimental would control whether we provide the declarations of experimental features in libc++.

Yes.

Okay, so I finally put together something that I think will get everyone’s support. Basically, what I’m proposing for now is just that we systematically provide deprecation warnings before we remove a feature, and we remove headers when they’re empty (instead of the weird trap we have right now).

There’s nothing else, it’s that simple! I created a Phab review implementing those changes – please comment on the review: https://reviews.llvm.org/D62428

Thanks,
Louis