[scope] Scope review starts on November 26th
Dear Boost community. The peer review of the proposed Boost.Scope will start on
26th of November and continue until December 5th. Boost.Scope is a small
library implementing utilities defined in
On Fri, Nov 24, 2023 at 12:58 PM Дмитрий Архипов via Boost
Boost.Scope is a small library implementing utilities defined in
from C++ Extensions for Library Fundamentals v3 with a few extensions.
So... "with a few extensions." I would like to have a discussion about this. Over the years I have seen little problems pop up with libraries that mirror C++ standard library components where we can't deprecate the library or suggest that users switch to the std alternative, because Boost has "added a few extensions." I can't recall any particular examples but I know they exist. Since this Boost.Scope is not yet published, do we really want to be adding extensions to std components? A common complaint is that Boost duplicates functionality that exists in the standard. If we offer extensions this only furthers the rift and creates friction for switching back and forth. What do you all think? Thanks, Vinnie
On 11/26/23 04:55, Vinnie Falco via Boost wrote:
On Fri, Nov 24, 2023 at 12:58 PM Дмитрий Архипов via Boost
wrote: Boost.Scope is a small library implementing utilities defined in
from C++ Extensions for Library Fundamentals v3 with a few extensions. So... "with a few extensions." I would like to have a discussion about this. Over the years I have seen little problems pop up with libraries that mirror C++ standard library components where we can't deprecate the library or suggest that users switch to the std alternative, because Boost has "added a few extensions." I can't recall any particular examples but I know they exist.
Since this Boost.Scope is not yet published, do we really want to be adding extensions to std components? A common complaint is that Boost duplicates functionality that exists in the standard. If we offer extensions this only furthers the rift and creates friction for switching back and forth.
What do you all think?
I think there's little point in introducing new libraries that are predetermined to be locked down to be strictly equivalent to the standard C++ components. We already have Boost.Compat for that. New libraries should allow for innovation and must not be limited by the current standard. The fact that some Boost libraries that now have standard counterparts have certain extensions is a good thing because it offers users a choice and provides them the functionality they need. The fact that the standard doesn't provide that functionality (provided that it is needed by users) is a deficiency of the standard, not the Boost library. Specifically regarding Boost.Scope, the extensions I made are what makes these components practically useful in my real code base. That is, I find the standard components too limiting or inconvenient to be useful in practice.
Andrey Semashev wrote:
Specifically regarding Boost.Scope, the extensions I made are what makes these components practically useful in my real code base. That is, I find the standard components too limiting or inconvenient to be useful in practice.
Can you please go into more detail on that? Maybe give a specific examples for the use cases in which the standard-proposed components don't work well but Boost.Scope does.
On 11/26/23 05:41, Peter Dimov via Boost wrote:
Andrey Semashev wrote:
Specifically regarding Boost.Scope, the extensions I made are what makes these components practically useful in my real code base. That is, I find the standard components too limiting or inconvenient to be useful in practice.
Can you please go into more detail on that? Maybe give a specific examples for the use cases in which the standard-proposed components don't work well but Boost.Scope does.
Majority of my scope guard uses are BOOST_SCOPE_FINAL. This means that most of the time I don't need the ability to cancel the scope guard and don't want to invent its name (especially when there are multiple scope guards in a function). I have a few cases where I need to create an inactive scope guard and activate it later - typically, based on some condition deeper within the function. I also have a case where I need to create a scope guard that is conditionally active, and whether it is active is decided elsewhere (e.g. passed into the function as a parameter). Although I currently don't use unique_resource, I was using it at some point and found resource traits to be useful - specifically, with POSIX file descriptors. I find the need to use make_unique_resource_checked to construct the unique resource a significant inconvenience and error-prone practice. We don't need to use such a helper function neither with smart pointers nor with optional<>, and it is easy to forget that we need to use it with unique_resource. (In case if anyone wonders, constructing `unique_resource(fd, &::close)` is likely incorrect because it will always call `::close` on the fd on destruction, even if it is invalid.) Also, the fact that `std::unique_resource` would have double the size of an fd (due to the added `bool`) bothers me. A note on why I'm no longer using unique_resource. It's because I now have a dedicated `posix_file` class that wraps an fd and also provides a set of operations on files that I need (read, write, etc.). I still think `unique_resource` is useful though, because using a `unique_resource` (or `unique_fd` that is provided by Boost.Scope) has a much lower cost than writing such a class. One would typically spend the time on writing a special class like `posix_file` when there are lots of places where he would need that extra functionality. When your interaction with fds is episodic, it is easier to just use `unique_fd` where needed.
On Sat, Nov 25, 2023 at 6:17 PM Andrey Semashev via Boost
I think there's little point in introducing new libraries that are predetermined to be locked down to be strictly equivalent to the standard C++ components.
Au contraire, mon ami; A Boost library which is "merely" strictly equivalent to its std counterpart offers one significant quantum of value: it can be used in versions of C++ which are older than the standard in which the std component was introduced.
The fact that some Boost libraries that now have standard counterparts have certain extensions is a good thing because it offers users a choice and provides them the functionality they need.
This might have been a convincing argument five years ago, but empirical evidence disproves this claim. No one is intentionally choosing Boost's error_code, filesystem, or thread over the std equivalent because of "the functionality they need." The reality is that people end up using the boost equivalent components because they are forced to. Either because an upstream library requires it, such as Asio, or because it is already in the existing code base. Users have clearly indicated that they vastly prefer the std component over the Boost one regardless of whether the boost component offers additional value. The only time the boost component is preferred, is when the additional functionality is so significant in the value that it brings, that it justifies the additional friction required to integrate the component. One example that comes to mind is Boost.Variant2. New features added to std-flavored boost components become incredibly annoying years later when a project wants to switch back to the std equivalent, perhaps because they were finally able to upgrade to the latest C++. They discover they have to perform a non-trivial refactoring of the code base because over time these additional features that we added end up getting relied upon and cannot be extricated easily. Every time I try to talk people into using Boost this issue of boost having copies of std components comes up and not in a positive way. In fact, I think from now on I will write a very short review which encourages to REJECT any proposed library which clones std components and adds or changes anything, unless the feature or modification is so incredible that it "walks on water." I look forward to seeing whether these vaunted Boost.Scope "additions" meet this criteria.
The fact that the standard doesn't provide that functionality (provided that it is needed by users) is a deficiency of the standard, not the Boost library.
Users vastly prefer even the "defective" std components over the theoretically-better boost components, simply by virtue of them being in the standard, with all of the benefits this brings. Education, documentation, ubiquity, and so on, for std components is orders of magnitude more robust than the boost equivalent. This more than makes up for any perceived deficiencies. Like it or not, vocabulary types and algorithms which make it into std are going to have an enormous advantage over any third party code. Thanks
On 11/26/23 06:27, Vinnie Falco wrote:
On Sat, Nov 25, 2023 at 6:17 PM Andrey Semashev via Boost
wrote: I think there's little point in introducing new libraries that are predetermined to be locked down to be strictly equivalent to the standard C++ components.
Au contraire, mon ami; A Boost library which is "merely" strictly equivalent to its std counterpart offers one significant quantum of value: it can be used in versions of C++ which are older than the standard in which the std component was introduced.
This has nothing to do with being strictly limited to the standard definition of the component. You can use `boost::optional` since C++03 whether or not it offers extensions compared to `std::optional`.
The fact that some Boost libraries that now have standard counterparts have certain extensions is a good thing because it offers users a choice and provides them the functionality they need.
This might have been a convincing argument five years ago, but empirical evidence disproves this claim. No one is intentionally choosing Boost's error_code, filesystem, or thread over the std equivalent because of "the functionality they need."
I am. Specifically, I'm using Boost.Atomic, Boost.Regex and some bits of Boost.Thread over the standard components because they either better fit my needs or offer better performance. I also find myself using Boost.Intrusive and `boost::intrusive_ptr` much more often than the standard containers and `std::shared_ptr`.
The reality is that people end up using the boost equivalent components because they are forced to. Either because an upstream library requires it, such as Asio, or because it is already in the existing code base. Users have clearly indicated that they vastly prefer the std component over the Boost one regardless of whether the boost component offers additional value.
The only time the boost component is preferred, is when the additional functionality is so significant in the value that it brings, that it justifies the additional friction required to integrate the component. One example that comes to mind is Boost.Variant2.
New features added to std-flavored boost components become incredibly annoying years later when a project wants to switch back to the std equivalent, perhaps because they were finally able to upgrade to the latest C++. They discover they have to perform a non-trivial refactoring of the code base because over time these additional features that we added end up getting relied upon and cannot be extricated easily.
Sorry, I don't get this logic. You used a library for many years, with all its features. Now a standard component appears that lacks some of the features you use. Yet you still decide to switch to it despite the inconveniences and lacking functionality. And somehow the library that served you well is to blame for your trouble? The way I see it, you (the one who decided to switch) is the one to blame in this situation. I don't mean this in an accusatory way, and there may be valid reasons to switch. But still it was your decision to switch despite the consequences, and thus you are the one responsible.
Every time I try to talk people into using Boost this issue of boost having copies of std components comes up and not in a positive way. In fact, I think from now on I will write a very short review which encourages to REJECT any proposed library which clones std components and adds or changes anything, unless the feature or modification is so incredible that it "walks on water." I look forward to seeing whether these vaunted Boost.Scope "additions" meet this criteria.
You are, of course, free to do so, including in case of Boost.Scope. But the way I see it, this is hindering innovation and would play towards Boost stagnation.
The fact that the standard doesn't provide that functionality (provided that it is needed by users) is a deficiency of the standard, not the Boost library.
Users vastly prefer even the "defective" std components over the theoretically-better boost components, simply by virtue of them being in the standard, with all of the benefits this brings. Education, documentation, ubiquity, and so on, for std components is orders of magnitude more robust than the boost equivalent. This more than makes up for any perceived deficiencies. Like it or not, vocabulary types and algorithms which make it into std are going to have an enormous advantage over any third party code.
I'd like to think everyone is free to make their own choice based on their own criteria and merits of each of the options. Availability of the standard library is an important advantage, but it is not ultimate. Personally, I find the standard library severely lacking, meaning I cannot reasonably write a serious project relying solely on the standard library and nothing else. I'd have to write a lot of code that I know exists and tested in other libraries like Boost, and I'd have to be mad not to try and reuse it. So you could say Boost is my natural extension of the standard library, something that I always have by my hand, just as easily reachable as the standard library. BTW, on the topic of innovation and stagnation, my other complaint about the standard library (or rather its implementations, every one of them) is that once a feature is implemented, it gets frozen because of ABI stability. Stable ABI is important, but because of it bugs like this[1] never get fixed. [1]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98978
On Sun, Nov 26, 2023 at 7:14 AM Andrey Semashev via Boost < boost@lists.boost.org> wrote:
On 11/26/23 06:27, Vinnie Falco wrote:
On Sat, Nov 25, 2023 at 6:17 PM Andrey Semashev via Boost
wrote: The fact that the standard doesn't provide that functionality (provided that it is needed by users) is a deficiency of the standard, not the Boost library.
Users vastly prefer even the "defective" std components over the theoretically-better boost components, simply by virtue of them being in the standard, with all of the benefits this brings. Education, documentation, ubiquity, and so on, for std components is orders of magnitude more robust than the boost equivalent. This more than makes up for any perceived deficiencies. Like it or not, vocabulary types and algorithms which make it into std are going to have an enormous advantage over any third party code.
I'd like to think everyone is free to make their own choice based on their own criteria and merits of each of the options. Availability of the standard library is an important advantage, but it is not ultimate. Personally, I find the standard library severely lacking, meaning I cannot reasonably write a serious project relying solely on the standard library and nothing else. I'd have to write a lot of code that I know exists and tested in other libraries like Boost, and I'd have to be mad not to try and reuse it. So you could say Boost is my natural extension of the standard library, something that I always have by my hand, just as easily reachable as the standard library.
BTW, on the topic of innovation and stagnation, my other complaint about the standard library (or rather its implementations, every one of them) is that once a feature is implemented, it gets frozen because of ABI stability. Stable ABI is important, but because of it bugs like this[1] never get fixed.
I don't disagree with your overall point (see my comment on opt-in), but it's simply untrue that things are *frozen* -- implying no changes are possible due to ABI constraints. Newer versions of optional support additional facilities (monadic interface) and I suspect you'll see support for references in 26. Yep, ABI updates prevent some changes, but not every change. Jeff
On 11/28/23 19:14, Jeff Garland via Boost wrote:
On Sun, Nov 26, 2023 at 7:14 AM Andrey Semashev via Boost < boost@lists.boost.org> wrote:
On 11/26/23 06:27, Vinnie Falco wrote:
On Sat, Nov 25, 2023 at 6:17 PM Andrey Semashev via Boost
wrote: The fact that the standard doesn't provide that functionality (provided that it is needed by users) is a deficiency of the standard, not the Boost library.
Users vastly prefer even the "defective" std components over the theoretically-better boost components, simply by virtue of them being in the standard, with all of the benefits this brings. Education, documentation, ubiquity, and so on, for std components is orders of magnitude more robust than the boost equivalent. This more than makes up for any perceived deficiencies. Like it or not, vocabulary types and algorithms which make it into std are going to have an enormous advantage over any third party code.
I'd like to think everyone is free to make their own choice based on their own criteria and merits of each of the options. Availability of the standard library is an important advantage, but it is not ultimate. Personally, I find the standard library severely lacking, meaning I cannot reasonably write a serious project relying solely on the standard library and nothing else. I'd have to write a lot of code that I know exists and tested in other libraries like Boost, and I'd have to be mad not to try and reuse it. So you could say Boost is my natural extension of the standard library, something that I always have by my hand, just as easily reachable as the standard library.
BTW, on the topic of innovation and stagnation, my other complaint about the standard library (or rather its implementations, every one of them) is that once a feature is implemented, it gets frozen because of ABI stability. Stable ABI is important, but because of it bugs like this[1] never get fixed.
I don't disagree with your overall point (see my comment on opt-in), but it's simply untrue that things are *frozen* -- implying no changes are possible due to ABI constraints. Newer versions of optional support additional facilities (monadic interface) and I suspect you'll see support for references in 26. Yep, ABI updates prevent some changes, but not every change.
Adding new features is relatively easy. But once they are added, they become effectively frozen.
Andrey Semashev wrote:
The reality is that people end up using the boost equivalent components because they are forced to. Either because an upstream library requires it, such as Asio, or because it is already in the existing code base. Users have clearly indicated that they vastly prefer the std component over the Boost one regardless of whether the boost component offers additional value.
The only time the boost component is preferred, is when the additional functionality is so significant in the value that it brings, that it justifies the additional friction required to integrate the component. One example that comes to mind is Boost.Variant2.
New features added to std-flavored boost components become incredibly annoying years later when a project wants to switch back to the std equivalent, perhaps because they were finally able to upgrade to the latest C++. They discover they have to perform a non-trivial refactoring of the code base because over time these additional features that we added end up getting relied upon and cannot be extricated easily.
Sorry, I don't get this logic. You used a library for many years, with all its features. Now a standard component appears that lacks some of the features you use. Yet you still decide to switch to it despite the inconveniences and lacking functionality. And somehow the library that served you well is to blame for your trouble?
The way I see it, you (the one who decided to switch) is the one to blame in this situation. I don't mean this in an accusatory way, and there may be valid reasons to switch. But still it was your decision to switch despite the consequences, and thus you are the one responsible.
Both sides have a point here. Boost things that differ slightly from their standard counterparts do eventually become a problem when they become obsolete and undermaintained. (Things that fall into this category to some extent are Bind, Function, Ratio, Chrono, to a lesser extent Thread, etc.) I would like, for instance, to replace the entire implementation of boost::bind with `using std::bind;`, but I can't due to subtle and sometimes not so subtle differences. E.g. boost::mem_fn uses get_pointer(p) instead of *p, which allows useful things, and people did take advantage of it. There's no reliable way to know whether anyone in the real world still relies on these extensions or not, so it's hard to figure out whether breaking their code is worth it. Boost.Function is similar; there are subtle differences in behavior and not subtle extensions (allocator support) so it can't be replaced with a using declaration either. I did recently go ahead and make boost::ratio a using declaration. This potentially broke the code of anyone relying on the Ratio extensions. Fortunately, those were guarded behind a macro, so their use was probably limited. I would very much have liked to replace Chrono with using declarations as well, but that doesn't seem possible at the moment. All that said... If a library is not going to become undermaintained and obsolete due to the author abandoning it at some point, is going to be actively developed, and offers significant functionality over the standard counterpart that cannot easily be replicated by the user (e.g. local_shared_ptr, thread interruption), then said library won't ever be replaceable with a using declaration, and none of the above applies.
On Tue, Nov 28, 2023 at 8:37 AM Peter Dimov via Boost
...
Some great points made here. I very much like the idea of Boost components which: 1. Mirror std equivalents 2. Give users of older C++ versions access to std-like components 3. Offer compelling improvements over their std counterparts Not every component is the same though. For example a `boost::thread` is most likely to be an implementation detail and not a type used in a public interface. On the other hand `boost::error_code` is fundamental and usually affects the entire public interface. Perhaps Boost.Scope has more flexibility than say, a boost::pmr::memory_resource in terms of how far in can deviate from the standard, simply because Boost.Scope types are more likely to be implementation details than public interfaces. I have yet to look closely at the library. Maybe it has some types which are fundamental (likely to appear in public APIs) and some which are not (more likely to appear as local variables). In this case the fundamental types should adhere more strictly to the standard. This goes beyond Boost.Scope and I would think it applicable to any proposed library. Thanks
On Sat, Nov 25, 2023 at 8:27 PM Vinnie Falco via Boost < boost@lists.boost.org> wrote:
On Sat, Nov 25, 2023 at 6:17 PM Andrey Semashev via Boost
wrote: I think there's little point in introducing new libraries that are predetermined to be locked down to be strictly equivalent to the standard C++ components.
Au contraire, mon ami; A Boost library which is "merely" strictly equivalent to its std counterpart offers one significant quantum of value: it can be used in versions of C++ which are older than the standard in which the std component was introduced.
Agree with this.
The fact that some Boost libraries that now have standard counterparts have certain extensions is a good thing because it offers users a choice and provides them the functionality they need.
This might have been a convincing argument five years ago, but empirical evidence disproves this claim. No one is intentionally choosing Boost's error_code, filesystem, or thread over the std equivalent because of "the functionality they need."
I think the canonical example actually is boost::thread. It had an interruption feature -- and maybe some other things I've forgotten -- that come up often. Probably now solved by jthread in c++20, but possibly not as cleanly. shared_ptr may be a similar case although recent std additions from Peter and friends may have closed the gap.
....
Every time I try to talk people into using Boost this issue of boost having copies of std components comes up and not in a positive way. In fact, I think from now on I will write a very short review which encourages to REJECT any proposed library which clones std components and adds or changes anything, unless the feature or modification is so incredible that it "walks on water." I look forward to seeing whether these vaunted Boost.Scope "additions" meet this criteria.
I haven't studied the scope additions compared to the TS yet, but it seems unlikely to get to the proposed bar. Perhaps there's a middle ground where the library can offer opt-in extensions but otherwise adhere to the standard interface? One good reason I can see in this case is that the Scope facilities are currently *only in a technical spec*, so if there's something compelling that's missing that could be changed before it's proposed for the standard. Getting some experience with that sort of thing is very valuable to making the standard better in the first place. For those that wanted to try the extensions the opt-in makes it clear that it's not going to match what we're guessing will go into the standard.
The fact that the standard doesn't provide that functionality (provided that it is needed by users) is a deficiency of the standard, not the Boost library.
Users vastly prefer even the "defective" std components over the theoretically-better boost components, simply by virtue of them being in the standard, with all of the benefits this brings. Education, documentation, ubiquity, and so on, for std components is orders of magnitude more robust than the boost equivalent. This more than makes up for any perceived deficiencies. Like it or not, vocabulary types and algorithms which make it into std are going to have an enormous advantage over any third party code.
Also very much agree with this... Jeff
Jeff Garland wrote:
I think the canonical example actually is boost::thread. It had an interruption feature -- and maybe some other things I've forgotten -- that come up often. Probably now solved by jthread in c++20, but possibly not as cleanly.
People are definitely still using Boost.Thread instead of <thread> because of interruption.
On Tue, Nov 28, 2023 at 8:07 AM Jeff Garland via Boost
Scope facilities are currently *only in a technical spec*, so if there's something compelling that's missing that could be changed before it's proposed for the standard. Getting some experience with that sort of thing is very valuable to making the standard better in the first place.
Good point. Going into committee with field experience in hand (e.g. "we made the enter and exit behaviors callables so they could be customized by the user") is very helpful for shaping additions and modifications to the standard library - a point I have been trying to emphasize for years. There's a conversation to be had about the committee completely ignoring existing practice but that's a topic for another thread. Thanks
niedz., 26 lis 2023 o 04:27 Vinnie Falco via Boost
On Sat, Nov 25, 2023 at 6:17 PM Andrey Semashev via Boost
wrote: I think there's little point in introducing new libraries that are predetermined to be locked down to be strictly equivalent to the standard C++ components.
Au contraire, mon ami; A Boost library which is "merely" strictly equivalent to its std counterpart offers one significant quantum of value: it can be used in versions of C++ which are older than the standard in which the std component was introduced.
The fact that some Boost libraries that now have standard counterparts have certain extensions is a good thing because it offers users a choice and provides them the functionality they need.
This might have been a convincing argument five years ago, but empirical evidence disproves this claim. No one is intentionally choosing Boost's error_code, filesystem, or thread over the std equivalent because of "the functionality they need."
The reality is that people end up using the boost equivalent components because they are forced to. Either because an upstream library requires it, such as Asio, or because it is already in the existing code base. Users have clearly indicated that they vastly prefer the std component over the Boost one regardless of whether the boost component offers additional value.
The only time the boost component is preferred, is when the additional functionality is so significant in the value that it brings, that it justifies the additional friction required to integrate the component. One example that comes to mind is Boost.Variant2.
New features added to std-flavored boost components become incredibly annoying years later when a project wants to switch back to the std equivalent, perhaps because they were finally able to upgrade to the latest C++. They discover they have to perform a non-trivial refactoring of the code base because over time these additional features that we added end up getting relied upon and cannot be extricated easily.
Every time I try to talk people into using Boost this issue of boost having copies of std components comes up and not in a positive way. In fact, I think from now on I will write a very short review which encourages to REJECT any proposed library which clones std components and adds or changes anything, unless the feature or modification is so incredible that it "walks on water." I look forward to seeing whether these vaunted Boost.Scope "additions" meet this criteria.
The fact that the standard doesn't provide that functionality (provided that it is needed by users) is a deficiency of the standard, not the Boost library.
Users vastly prefer even the "defective" std components over the theoretically-better boost components, simply by virtue of them being in the standard, with all of the benefits this brings. Education, documentation, ubiquity, and so on, for std components is orders of magnitude more robust than the boost equivalent. This more than makes up for any perceived deficiencies. Like it or not, vocabulary types and algorithms which make it into std are going to have an enormous advantage over any third party code.
Maybe this argument applies with different weight for vocabulary and non-vocabulary types. My understanding of a vocabulary type is that it is one that you would likely expose in your interfaces, and have two (or more) libraries communicate via it. optional, shared_ptr, variant, error_code are types of this sort. For those types you would strongly prefer to use the std version, because it is likely that other 3rd party libraries will also use the std version. scope_guard is a type you will use internally in your implementation, so whether you pick the Boost version or the std version is your private business. Regards, &rzej;
Thanks
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On 28/11/2023 18:41, Andrzej Krzemienski via Boost wrote:
Users vastly prefer even the "defective" std components over the theoretically-better boost components, simply by virtue of them being in the standard, with all of the benefits this brings. Education, documentation, ubiquity, and so on, for std components is orders of magnitude more robust than the boost equivalent. This more than makes up for any perceived deficiencies. Like it or not, vocabulary types and algorithms which make it into std are going to have an enormous advantage over any third party code.
I think the pendulum may swing back in the next few years. To explain why, it's probably not widely known yet, so I shall make it so now: I intend to quit LEWG when the C++ 26 IS cutoff occurs early 2025, and I will only be around LWG until my papers finish wording. After that I'm done with WG21, all my papers not into LWG I'm dropping on the floor. I've had enough with how things are done at WG21 - it's a poor use of my scarce free time. Why? I think WG21 has become ever increasingly awful at library standardisation since C++ 14 onwards. There is a lot of design-by-committee, and if we were good at it, great, but we really really are not good at it. Every major standard library addition since C++ 14 onwards has had at least one easily fixable major design flaw in my opinion. Boost has repeatedly moved to implement those standard library additions, but **fixed** WG21's mistakes either immediately or within a short period of time. One of the most egregious examples in my opinion is `std::variant` where the whole valueless by exception footgun was 100% avoidable, and Boost.Variant2 immediately eliminated that footgun. This is hardly an isolated example: Boost's `shared_ptr` is less footgunny than `std::shared_ptr`. Boost's Optional is arguably more footgunny than `std::optional`, but a lot of people think its extensions are worth it. I could go on (e.g. `boost::error_code` over the fundamentally unsafe `std::error_code`), but you get the idea. I think that as WG21's increasing dysfunction at standardising library becomes more obvious to the C++ ecosystem, the need for fixed standard library facilities will grow because the standardised ones will become toxic to use in newly written code. I think Boost is as good as anywhere to be the natural source for fixed standardised library facilities. So **PLEASE** Boost keep doing what it's doing, keep standardising standardised library facilities, because you're a hell of a lot better at it than WG21 in my opinion. (For anybody interested, I'll be moving in 2025 over to the C committee, where I think my time and energies will be far more effectively used than what WG21 is capable of allowing me to achieve. I actually believe I'll have more impact on C++ from WG14 than I ever could at WG21 due to WG21 having become so dysfunctional. Before anybody emails privately to ask, yes Herb and Inbal knows my thoughts and feelings here in substantial detail, and they both know I'm moving on in 2025) Niall
On Tue, Nov 28, 2023 at 1:36 PM Niall Douglas via Boost < boost@lists.boost.org> wrote:
On 28/11/2023 18:41, Andrzej Krzemienski via Boost wrote:
Users vastly prefer even the "defective" std components over the theoretically-better boost components, simply by virtue of them being in the standard, with all of the benefits this brings. Education, documentation, ubiquity, and so on, for std components is orders of magnitude more robust than the boost equivalent. This more than makes up for any perceived deficiencies. Like it or not, vocabulary types and algorithms which make it into std are going to have an enormous advantage over any third party code.
I think the pendulum may swing back in the next few years. ...
I think that as WG21's increasing dysfunction at standardising library becomes more obvious to the C++ ecosystem, the need for fixed standard library facilities will grow because the standardised ones will become toxic to use in newly written code. I think Boost is as good as anywhere to be the natural source for fixed standardised library facilities.
Say what you want but Boost has lost that role, which is part of the dysfunction at WG21. If you're a committee member and you're trying to evaluate libraries you're getting what -- godbolt links to implementations? How much user experience or unit testing is there? Can you realistically see how library components work together? No, obviously.
So **PLEASE** Boost keep doing what it's doing, keep standardising standardised library facilities, because you're a hell of a lot better at it than WG21 in my opinion.
We still do a bit of that, but mostly not because most proposals simply bypass boost at this point. This includes proposals from major past contributors. I'll be making proposals in the future to change Boost, but suffice to say just doing what we're doing won't cut it. And there's still a lot of WG21 here, btw -- Boost was started by WG21 members to fix WG21 libraries -- and many of us still do our best to do both. Jeff
Jeff Garland wrote:
On Tue, Nov 28, 2023 at 1:36 PM Niall Douglas via Boost < boost@lists.boost.org> wrote:
So **PLEASE** Boost keep doing what it's doing, keep standardising standardised library facilities, because you're a hell of a lot better at it than WG21 in my opinion.
We still do a bit of that, but mostly not because most proposals simply bypass boost at this point.
This hasn't been working very well for WG21. The trend is towards proposals named P00xxR38 with quality often not matching the average rejected Boost library. LEWG is not an efficient mechanism for designing libraries, because iterating here is vastly faster and better than iterating at WG21 meetings. (But to ensure smooth sailing one would nowadays need to remember to keep extensive design notes on how the library came to be this way and not some other, in order to produce these on demand when asked in LEWG. This used to be less needed in the past when LWG and Boost significantly overlapped.)
On Tue, Nov 28, 2023 at 7:34 PM Peter Dimov via Boost
Jeff Garland wrote:
On Tue, Nov 28, 2023 at 1:36 PM Niall Douglas via Boost < boost@lists.boost.org> wrote:
So **PLEASE** Boost keep doing what it's doing, keep standardising standardised library facilities, because you're a hell of a lot better at it than WG21 in my opinion.
We still do a bit of that, but mostly not because most proposals simply bypass boost at this point.
This hasn't been working very well for WG21. The trend is towards proposals named P00xxR38 with quality often not matching the average rejected Boost library.
LEWG is not an efficient mechanism for designing libraries, because iterating here is vastly faster and better than iterating at WG21 meetings.
I agree with the conclusion that WG21 should stop designing libraries. And should also stop contemplating non-foundational libraries. But until there's a reasonable library ecosystem using STD as a distribution mechanism will continue. Boost happens to be one of the better such ecosystem distribution mechanisms, still. -- -- René Ferdinand Rivera Morell -- Don't Assume Anything -- No Supone Nada -- Robot Dreams - http://robot-dreams.net
On Tue, Nov 28, 2023 at 7:24 PM René Ferdinand Rivera Morell via Boost < boost@lists.boost.org> wrote:
On Tue, Nov 28, 2023 at 7:34 PM Peter Dimov via Boost
wrote: LEWG is not an efficient mechanism for designing libraries, because iterating here is vastly faster and better than iterating at WG21 meetings.
I agree with the conclusion that WG21 should stop designing libraries.
It's clear LEWG isn't designing libraries. They're completely dependent on authors to bring a design and modify it in a way that makes the committee happy. My conclusion is that LEWG isn't great at reviewing libraries -- and with libraries going around Boost they miss the review and likely the user base that confirms that the library makes sense. Note that in my experience a decent percentage of the library work is actually modifying the existing library.
And should also stop contemplating non-foundational libraries.
Please define what you think that is. Would std::process qualify, because I'd like to think it does? I'm assuming you'd agree that std::format/std::print are important?
But until there's a reasonable library ecosystem using STD as a distribution mechanism will continue. Boost happens to be one of the better such ecosystem distribution mechanisms, still.
It's fine -- but I'd argue that there's a lot of people that avoid boost like the plague. It doesn't matter if that's fully rationale, but it's a perception that clearly is out there. Jeff
On Tue, Nov 28, 2023 at 6:34 PM Peter Dimov via Boost
This hasn't been working very well for WG21. The trend is towards proposals named P00xxR38 with quality often not matching the average rejected Boost library.
To be fair, most of the R38 libraries are large and difficult. But obviously I think something important has been lost here and I'd like to restore it. Mostly I think that's libraries in the hands of lots of users, including committee members as users.
LEWG is not an efficient mechanism for designing libraries, because iterating here is vastly faster and better than iterating at WG21 meetings.
Indeed. And importantly, we have actual real users to find problems...
(But to ensure smooth sailing one would nowadays need to remember to keep extensive design notes on how the library came to be this way and not some other, in order to produce these on demand when asked in LEWG.
I don't see this part as a bad thing -- even Boost is hit and miss and documenting decisions. It's a lot of work.
This used to be less needed in the past when LWG and Boost significantly overlapped.)
I assume you mean when LEWG basically didn't exist and it was *just LWG*. For sure. But the community has expanded past that -- and so we need to find new ways in my view to do the work that can't realistically be done in LEWG in a place like Boost. Apparently new authors don't find being in Boost of value -- I'm hoping we can change that going forward, we'll see. Jeff
On Tue, Nov 28, 2023 at 6:49 PM Jeff Garland via Boost < boost@lists.boost.org> wrote:
I assume you mean when LEWG basically didn't exist and it was *just LWG*
This structure (with "just LWG") was vastly superior to the current model (LEWG + LWG) in terms of delivering the best value for C++ users. Because when it was just LWG, the group was composed also of great library designers in addition to wordsmiths. By creating the new group LEWG, the great library designers are stuck in LWG where they cannot change anything given to them by LEWG, and meanwhile LEWG is populated by people who just want to "get their library into std" for various personal reasons. Furthermore having "just LWG" created a natural bottleneck: not every library could go in, so decisions weighing the benefits and comparing what brings the best value for the limited committee resources were made more conscientiously. Thanks
On Tue, Nov 28, 2023 at 9:24 PM Vinnie Falco
On Tue, Nov 28, 2023 at 6:49 PM Jeff Garland via Boost < boost@lists.boost.org> wrote:
I assume you mean when LEWG basically didn't exist and it was *just LWG*
This structure (with "just LWG") was vastly superior to the current model (LEWG + LWG) in terms of delivering the best value for C++ users. Because when it was just LWG, the group was composed also of great library designers in addition to wordsmiths. By creating the new group LEWG, the great library designers are stuck in LWG where they cannot change anything given to them by LEWG, and meanwhile LEWG is populated by people who just want to "get their library into std" for various personal reasons.
This isn't really the case. The truth is that the goals were much more limited -- due to the lack of experience in the external world. And the implementers were also more limited. clang, for example, simply didn't exist. And compilers mostly couldn't deal with boost. In the modern era, if you believe that 'the regular LWG experts' don't input into LEWG -- well that would be mistaken. In fact, most of the LWG core forces LEWG to clean up the design before it arrives on our doorstep. Well actually, by policy they've done tat. And, frankly, if we don't like it because it hase design issues -- we send it back. I'm not arguing that the way we work is ideal -- far from it. We have to consider the human aspects of how many brains we have, how much time we have, etc. Boost is irreplaceable in the aspect that so many brains - aka users -- see the libraries before we standardize. We need to find ways to make that aspect of boost more relevant again.
Furthermore having "just LWG" created a natural bottleneck: not every library could go in, so decisions weighing the benefits and comparing what brings the best value for the limited committee resources were made more conscientiously.
It wasn't a bottleneck for a long time including c++11 -- and it isn't again now as LWG has caught up with LEWG largely. It was just different in that the total size of the group evaluating proposals was less than 20 people -- not the case now. In the large, I consider more brains a better. But you have to ask - how many have done the deep dive we typically see in boost reviews? Have you even read the paper before giving an LEWG review comment? I fear the bigger issue here is that tiktok attention span defines most people these days. Having a proving ground of real user experience allays those concerns because it's people that are invested in the details of how it works. Jeff
On 29/11/2023 05:37, Jeff Garland via Boost wrote:
But you have to ask - how many have done the deep dive we typically see in boost reviews? Have you even read the paper before giving an LEWG review comment? I fear the bigger issue here is that tiktok attention span defines most people these days. Having a proving ground of real user experience allays those concerns because it's people that are invested in the details of how it works.
Last few meetings at LEWG I find myself repeatedly thinking "this person hasn't read the paper". And not just for my own papers, for a majority of papers. R0's and R1's get read. R14's do not in my experience. Something I noticed about Titus when he was chair was he always seemed to have read the revision of the paper being discussed that day in detail, and had a good on-the-day knowledge of where things were and how forward progress could be maximised. I know some felt as a result papers got pushed through too quickly by Titus, and a more reflective slower process would have produced higher quality results with fewer missing parts and footguns. However if a majority of the room does not read the latest revision of a paper, it's hard to produce higher quality results no matter how slow a process you use. There is an argument therefore to keep revisions well below ten, and either push stuff through faster or reject entirely much earlier. Niall
On 11/29/23 15:05, Niall Douglas via Boost wrote:
On 29/11/2023 05:37, Jeff Garland via Boost wrote:
But you have to ask - how many have done the deep dive we typically see in boost reviews? Have you even read the paper before giving an LEWG review comment? I fear the bigger issue here is that tiktok attention span defines most people these days. Having a proving ground of real user experience allays those concerns because it's people that are invested in the details of how it works.
Last few meetings at LEWG I find myself repeatedly thinking "this person hasn't read the paper". And not just for my own papers, for a majority of papers. R0's and R1's get read. R14's do not in my experience.
Something I noticed about Titus when he was chair was he always seemed to have read the revision of the paper being discussed that day in detail, and had a good on-the-day knowledge of where things were and how forward progress could be maximised.
I know some felt as a result papers got pushed through too quickly by Titus, and a more reflective slower process would have produced higher quality results with fewer missing parts and footguns. However if a majority of the room does not read the latest revision of a paper, it's hard to produce higher quality results no matter how slow a process you use. There is an argument therefore to keep revisions well below ten, and either push stuff through faster or reject entirely much earlier.
I'm not a committee member, just an observer from the outside, but it looks to me that people that aren't familiar with the proposal should abstain from the discussion. And if those people constitute the majority of the room then either the proposal discussion should be rescheduled to a later meeting or the room should be dismissed to do their homework. I realize that most of these people are likely busy and there are lots of proposals going, but discussing something that not everyone is familiar with is simply not productive. And if that means that the committee is a bottleneck, then split the committee into more parallel groups that focus on separate more localized domains.
Andrey Semashev wrote:
I'm not a committee member, just an observer from the outside, but it looks to me that people that aren't familiar with the proposal should abstain from the discussion. And if those people constitute the majority of the room then either the proposal discussion should be rescheduled to a later meeting or the room should be dismissed to do their homework.
That's not going to work. You go to Kona and the committee is like mate, we haven't bothered to read your paper, why don't you wait six months and come to Tokyo instead.
On 11/29/23 16:18, Peter Dimov via Boost wrote:
Andrey Semashev wrote:
I'm not a committee member, just an observer from the outside, but it looks to me that people that aren't familiar with the proposal should abstain from the discussion. And if those people constitute the majority of the room then either the proposal discussion should be rescheduled to a later meeting or the room should be dismissed to do their homework.
That's not going to work. You go to Kona and the committee is like mate, we haven't bothered to read your paper, why don't you wait six months and come to Tokyo instead.
Right, so why was the paper scheduled for discussion then? They do put up a list of what will be discussed and voted, don't they? And if they do schedule the paper, and still don't read it, and especially if that happens on a regular basis then that shows that the committee is unqualified for the job.
On 29/11/2023 13:18, Peter Dimov via Boost wrote:
Andrey Semashev wrote:
I'm not a committee member, just an observer from the outside, but it looks to me that people that aren't familiar with the proposal should abstain from the discussion. And if those people constitute the majority of the room then either the proposal discussion should be rescheduled to a later meeting or the room should be dismissed to do their homework.
That's not going to work. You go to Kona and the committee is like mate, we haven't bothered to read your paper, why don't you wait six months and come to Tokyo instead.
The chair advertises in advance what papers will be seen at a meeting, those who are in the room at the time are on person's honour they've done the due diligence involved to speak usefully about a paper. What happens in practice is a lot of people in the room when the paper changes load up the paper on their laptops, scan it very quickly, and then make somewhat informed comments with varying signal to noise ratios. For my papers which went to normative wording, I decided to drop all arguments about design, and just list out a condensed design summary as LEWG agreed (in some case years ago), the change revision log since then, and the current proposed normative wording. This prevents rapid page scanning in the way people are used to, though the condensed design summary is intended to let them get up to speed within three pages of reading intensively instead of forty pages with far more words. I therefore get constant comments and complaints about me having "unhelpfully" removed the forty plus pages of arguments about design. Anybody who makes such a comment is effectively saying "no I didn't read your paper before right just now", though they probably don't realise that they're admitting that in public. In the end, you can't make people in the room study a paper beforehand, or if they didn't, to not make unproductive comments. The current process is fundamentally broken in my opinion. WG21 should adopt a better one, ideally one not based on library proposal papers consisting of dozens to hundreds of pages of proposed normative wording. We have a far more terse library specification language available to us than ISO normative wording. It's called "reference implementation". Niall
On Wed, Nov 29, 2023 at 5:14 AM Andrey Semashev via Boost < boost@lists.boost.org> wrote:
I'm not a committee member, just an observer from the outside, but it looks to me that people that aren't familiar with the proposal should abstain from the discussion.
The main issue that I see is that the structure of the committee itself is not aligned with the needs of users. There is no feedback mechanism in place which pushes members in the right direction. There is no qualitative analysis regarding the benefits versus cost of approving a paper. There are no objective measures for comparing two papers to determine which one does the most good. After a paper is accepted and the feature deployed, there is no retrospective quantitative analysis of the achieved benefits versus the expected benefits. There is no process of natural selection which ensures the most productive and talented individuals are prioritized over individuals who contribute little. In the "real world" a business that does not serve the needs of its customers goes bankrupt. But when WG21 fails to serve the needs of C++ users, nothing happens. In fact most of the time they don't even know they are failing the community, as everyone is pursuing their own self-interests. Thanks
Vinnie Falco wrote:
On Wed, Nov 29, 2023 at 5:14 AM Andrey Semashev via Boost < boost@lists.boost.org> wrote:
I'm not a committee member, just an observer from the outside, but it looks to me that people that aren't familiar with the proposal should abstain from the discussion.
The main issue that I see is that the structure of the committee itself is not aligned with the needs of users. There is no feedback mechanism in place which pushes members in the right direction. There is no qualitative analysis regarding the benefits versus cost of approving a paper. There are no objective measures for comparing two papers to determine which one does the most good. After a paper is accepted and the feature deployed, there is no retrospective quantitative analysis of the achieved benefits versus the expected benefits. There is no process of natural selection which ensures the most productive and talented individuals are prioritized over individuals who contribute little.
In the "real world" a business that does not serve the needs of its customers goes bankrupt. But when WG21 fails to serve the needs of C++ users, nothing happens. In fact most of the time they don't even know they are failing the community, as everyone is pursuing their own self-interests.
I don't think this theory has any explanatory power. Everything above applies equally well to the C++98 committee or the C++11 committee, yet the result was entirely different.
On 29/11/2023 18:15, Peter Dimov via Boost wrote:
I don't think this theory has any explanatory power. Everything above applies equally well to the C++98 committee or the C++11 committee, yet the result was entirely different.
1. There was lots more low hanging fruit for 11.
2. 11 took a lot more time in the cooker.
3. 11 was originally much much bigger, but had a round of drastic
pruning applied before 11 became 11. Anything contentious, not quite
fully baked etc, got stripped out.
4. 11 borrowed very heavily from existing well established practice, and
didn't go monkeying around with it in the name of "modernisation".
There were still some big design mistakes in 11 - I still find
`<random>` very unfortunate and entirely avoidable at the time, unlike
`
On 11/30/23 01:03, Niall Douglas via Boost wrote:
There were still some big design mistakes in 11 - I still find `<random>` very unfortunate and entirely avoidable at the time, unlike `
` or initialiser lists where the defects were not obvious initially. `<regex>` and ` ` probably couldn't have been predicted easily in advance, at their time they seemed reasonable.
Could you elaborate on the design problems of the above components? Or perhaps, you have a link where these problems are described? I'm interested in initializer lists, regex and unordered_map in particular.
On 29/11/2023 22:20, Andrey Semashev via Boost wrote:
On 11/30/23 01:03, Niall Douglas via Boost wrote:
There were still some big design mistakes in 11 - I still find `<random>` very unfortunate and entirely avoidable at the time, unlike `
` or initialiser lists where the defects were not obvious initially. `<regex>` and ` ` probably couldn't have been predicted easily in advance, at their time they seemed reasonable. Could you elaborate on the design problems of the above components?
One could write a book on them, so I shall have to be terse.
Or perhaps, you have a link where these problems are described? I'm interested in initializer lists, regex and unordered_map in particular.
Initialiser lists don't initialise in reliable ways. I think Arthur and others did a bunch of blog posts about it. They also didn't initially cope well with static const runtime representations, which has since been partially fixed, but what we've ended up with is far from what they should have been had they been thought through better. They also have weird quirks in what they can deduce without being hinted at, and what they can't. And finally, compilers are really, really slow when fed large initialiser lists, I was told once that's because they mandate O(N^2) complexity which was surely foreseeable. Regex is templates based, and anything templates based has horrible ABI consequences if you cannot break ABI. You can't safely standardise something templates based without getting it absolutely 100% right from the beginning, and as any user of std::regex will testify, we did not. You'd think we would have learned from that, but no we keep standardising large templates based things and then experiencing the same kiss of death by ABI. So not only was that foreseeable, but we are still repeating the same. Unordered_map gives stronger guarantees than it needs to for 99% of code, and that makes it slow. Slightly relaxing its guarantees would have avoided that problem entirely, and still kept iterator stability etc. That was surely foreseeable. Obviously all the above is much easier with hindsight. However, having been on the committee for five years I have again and again and again seen somebody who really knows what they're talking about warn of consequences down the line, it might avoid a bad decision that meeting but next meeting they forget and that person isn't in the room that time and so it gets changed for the worse. I don't know if the same happened for all those facilities above, but I would suspect it did from everything I've seen. The problem with consensus based decision making is some people really ought to have 10x the votes of anybody else, but if they fail to persuade the room on the day or are in a different room, then bad decisions get taken. I can't speak of details of a specific meeting (ISO rules), but a formative moment for me was when discussing a small but key new feature in the C++ 23 standard. We had three standard library implementers in the room who pleaded for a certain stronger guarantee in the design, along with all of the Boost crowd, and yet we couldn't persuade the room so there was no consensus for change. Two weeks ago at work I had to completely reimplement from scratch that standard library feature in order to ensure that stronger guarantee because the standard library one does not. I was thinking ruefully of that day in WG21, wondering what the hell am I doing there? I don't think I'm making the world a better place by directing my energies at there, anyway. Niall
Niall Douglas wrote:
There were still some big design mistakes in 11 - I still find `<random>` very unfortunate and entirely avoidable at the time,
<random> is mostly fine. The generators and the concepts reflect the state of the art as it was then, and aren't entirely broken even today.
On 29/11/2023 22:21, Peter Dimov via Boost wrote:
Niall Douglas wrote:
There were still some big design mistakes in 11 - I still find `<random>` very unfortunate and entirely avoidable at the time,
<random> is mostly fine. The generators and the concepts reflect the state of the art as it was then, and aren't entirely broken even today.
I really have to disagree :) There is this axis randomness: 1. Predictable randomness from a specified starting state. 2. Unpredictable randomness with same semantics on all architectures. There is also the quality vs fast axis. On the quality vs fast axis, I could just about agree with you about <random>. On that other axis though, <random> is a complete design failure. One needs the ability to copy states, serialise and deserialise states, and to get identical output on all architectures and platforms for a given starting state. One also must not have an engine perform 20x worse on one platform than another if one is to write usefully portable code. That first axis was entirely foreseeable before and during standardisation, and only a few small design changes would have enabled it. Niall
Niall Douglas wrote:
On 29/11/2023 22:21, Peter Dimov via Boost wrote:
Niall Douglas wrote:
There were still some big design mistakes in 11 - I still find `<random>` very unfortunate and entirely avoidable at the time,
<random> is mostly fine. The generators and the concepts reflect the state of the art as it was then, and aren't entirely broken even today.
I really have to disagree :)
There is this axis randomness:
1. Predictable randomness from a specified starting state.
2. Unpredictable randomness with same semantics on all architectures.
There is also the quality vs fast axis.
On the quality vs fast axis, I could just about agree with you about <random>.
On that other axis though, <random> is a complete design failure. One needs the ability to copy states, serialise and deserialise states, and to get identical output on all architectures and platforms for a given starting state.
One also must not have an engine perform 20x worse on one platform than another if one is to write usefully portable code.
I don't understand your objections, sorry. Are you saying that the generators in <random> don't offer the ability to copy, serialize, deserialize and give identical output? Because they do. Which engine performs 20x worse?
On 30/11/2023 00:03, Peter Dimov via Boost wrote:
On that other axis though, <random> is a complete design failure. One needs the ability to copy states, serialise and deserialise states, and to get identical output on all architectures and platforms for a given starting state.
One also must not have an engine perform 20x worse on one platform than another if one is to write usefully portable code.
I don't understand your objections, sorry.
Are you saying that the generators in <random> don't offer the ability to copy, serialize, deserialize and give identical output? Because they do.
They do within the same execution of a program, but not across executions, or across standard libraries, or across architectures. Given its simplicity, I have never understood how a linear congruential engine's state couldn't have been given that added guarantee. I don't know why all PRNGs aren't required to be TriviallyCopyable and be noexcept on all functions and cannot block (i.e. no dynamic memory allocation allowed). Then I could send a PRNG state down a pipe, for example. Or I could call the PRNG from an async signal handler situation. That latter use case might sound unlikely, but it's more useful than you'd think if you're writing async signal handler code.
Which engine performs 20x worse?
I came badly unstuck with mt19937 one time. On one architecture it was 20x slower AND produced completely different output for a specific seed. Reading https://eel.is/c++draft/rand.eng.mers however, I believe that was non-conforming to the standard, and it was a long time ago now. So I'm going to chalk that up to bad QoI back in the day. Obviously there are much better quality and faster PRNGs than mt19937 nowadays, and it's a shame they're not in <random>, but for that somebody would have to write a paper. I think it's long overdue for common crypto PRNGs too. Niall
Niall Douglas wrote:
I don't understand your objections, sorry.
Are you saying that the generators in <random> don't offer the ability to copy, serialize, deserialize and give identical output? Because they do.
They do within the same execution of a program, but not across executions, or across standard libraries, or across architectures. Given its simplicity, I have never understood how a linear congruential engine's state couldn't have been given that added guarantee.
Not sure what you're talking about, sorry. All that is guaranteed. E.g. https://godbolt.org/z/a17oboMMq #include <random> #include <sstream> #include <iostream> int main() { std::mt19937 e1( 5 ); std::stringstream ss; ss << e1; std::mt19937 e2; ss >> e2; std::cout << e1() << std::endl; std::cout << e2() << std::endl; } The output of this program is fully specified by the standard.
I came badly unstuck with mt19937 one time. On one architecture it was 20x slower AND produced completely different output for a specific seed.
Not much WG21 can do about that. It's just a buggy implementation.
On Wed, Nov 29, 2023 at 11:03 PM Niall Douglas via Boost < boost@lists.boost.org> wrote:
There were still some big design mistakes in 11
Isn't that in part what the proposal(s) to break backward compatibility to fix mistakes is/are about? The recognition that mistakes will be made, and we can opt-in explicitly to the fixes? I can't comment on WG21's effectiveness or not. So this is maybe off-topic. But wouldn't having editions of the language allow for more flexibility regarding BC? [1]: https://thenewstack.io/bjarne-stroustrups-plan-for-bringing-safety-to-c/ [2]: https://vittorioromeo.info/index/blog/fixing_cpp_with_epochs.html
Le 2023-11-30 10:07, Dominique Devienne via Boost a écrit :
On Wed, Nov 29, 2023 at 11:03 PM Niall Douglas via Boost < boost@lists.boost.org> wrote:
There were still some big design mistakes in 11
Isn't that in part what the proposal(s) to break backward compatibility to fix mistakes is/are about? The recognition that mistakes will be made, and we can opt-in explicitly to the fixes?
I can't comment on WG21's effectiveness or not. So this is maybe off-topic. But wouldn't having editions of the language allow for more flexibility regarding BC?
I don't get how it would work regarding ABI/BC. It looks like it would allows solving issues within the language itself (like the uniform initialization mess), but i fail to see how it would allows fixing design issues within the standard library. Or are you suggesting that we have std11, std14, std17 namespaces for standard components?
[2]: https://vittorioromeo.info/index/blog/fixing_cpp_with_epochs.html
He makes a great point by saying that *if the Standard committee doesn’t do this, someone else will.*. To me it looks just like what Herb Sutter's cppfront is about. Regards, Julien
On Tue, Nov 28, 2023 at 9:37 PM Jeff Garland
It wasn't a bottleneck for a long time including c++11 -- and it isn't again now as LWG has caught up with LEWG largely.
My point is that having the bottleneck is a GOOD thing, because it greatly slows the rate at which C++ can be made worse. WG21 is a failed institution, the bureaucratic structure is incapable of maintaining the long-term health of the standard. Thanks
On 29/11/2023 04:24, Vinnie Falco via Boost wrote:
On Tue, Nov 28, 2023 at 6:49 PM Jeff Garland via Boost < boost@lists.boost.org> wrote:
I assume you mean when LEWG basically didn't exist and it was *just LWG*
This structure (with "just LWG") was vastly superior to the current model (LEWG + LWG) in terms of delivering the best value for C++ users. Because when it was just LWG, the group was composed also of great library designers in addition to wordsmiths. By creating the new group LEWG, the great library designers are stuck in LWG where they cannot change anything given to them by LEWG, and meanwhile LEWG is populated by people who just want to "get their library into std" for various personal reasons.
Furthermore having "just LWG" created a natural bottleneck: not every library could go in, so decisions weighing the benefits and comparing what brings the best value for the limited committee resources were made more conscientiously.
I would go further than that Vinnie - back when all of WG21 sat in the same room, library and language worked together a lot better. The current situation at WG21 - as proved in multiple votes over multiple years - is that Library have diametrically opposite opinions on what is important in many important topics than Language. This manifests in EWG refusing to consider language changes requested by Library, thus forcing Library to either make do or invent some hidious metaprogramming hack which adds seconds per compilation unit because nobody over in Language will entertain that Library might have valid concerns. You then get complaints from some in EWG that Library is "doing all the wrong things", and "only if it were run more like EWG". Obviously returning everybody to a single room isn't practical. But I also think using the same processes for Library as for Language is a bad move. Library isn't like Language, it should have its own unique and quite different processes in my opinion. In particular, I think Library should gain the power to change the language where it suits Library, and EWG removed from that part entirely. That will be seen as incenduary I am sure, however I think we would have long ago solved library ABI stability mitigations and lightweight exception handling if Library were allowed to decide some parts of language design. Niall
On Sat, Nov 25, 2023 at 7:27 PM Vinnie Falco
In fact, I think from now on I will write a very short review which encourages to REJECT any proposed library which clones std components and adds or changes anything, unless the feature or modification is so incredible that it "walks on water."
With respect to Boost.Scope, given the meaningful conversations taking place and given that Boost can serve as a vital counterweight to wg21 misadventures, I take back this statement above as it applies to this review. I am very happy to see a robust debate from key folks regarding the specifics of the library. The other people are correct; this design analysis is crucial for vetting designs aimed at standardization and it is great that Boost can still serve in this role since the Boost review process is still obviously superior to the alternatives. Thanks
Andrey Semashev wrote:
Specifically regarding Boost.Scope, the extensions I made are what makes these components practically useful in my real code base. That is, I find the standard components too limiting or inconvenient to be useful in practice.
You have a section in the documentation that compares Scope to ScopeExit, but I don't see a comparison against the proposed standard components. It might be useful to have one, where the rationale for the additions could naturally fit.
On 11/26/23 15:53, Peter Dimov via Boost wrote:
Andrey Semashev wrote:
Specifically regarding Boost.Scope, the extensions I made are what makes these components practically useful in my real code base. That is, I find the standard components too limiting or inconvenient to be useful in practice.
You have a section in the documentation that compares Scope to ScopeExit, but I don't see a comparison against the proposed standard components.
It might be useful to have one, where the rationale for the additions could naturally fit.
I can add a section discussing differences from the Library Fundamentals TS, though maybe not in the form of a table. https://github.com/Lastique/scope/issues/5 I listed the extensions in my initial announcement of the library. Here they are, for convenience: * A new scope_final scope guard, which is a more lightweight alternative to scope_exit. It is accompanied with the BOOST_SCOPE_FINAL macro that allows to simplify scope guard declaration syntax. * Scope guards can be activated/deactivated multiple times. * Scope guards can be created inactive initially. * Scope guard factory functions, for compatibility with C++11. * Support for custom condition functions for checking scope guards. This, for example, allows one to check for error codes instead of exceptions in scope_fail/scope_success. * Support for optional resource traits in unique_resource wrapper, which improves usage with resources having unallocated values. * unique_resource supports swapping. * unique_resource supports dereferencing for any resource types that support dereferencing, not only pointers. * More flexible constructors for unique_resource.
I have also posted review announcements on Reddit and in Cpplang Slack workspace. Here are some comments I've received: 1. Given void f(); int main() { auto a = boost::scope::make_scope_fail(f); boost::scope::scope_fail b(f); } Only the declaration of b compiles. The one of a fails. I think the one of a should compile, too. Something like std::decay instead of typename std::remove_cv< typename std::remove_reference< F >::type
::type at https://github.com/Lastique/scope/blob/develop/include/boost/scope/scope_exi...
2. According to http://eel.is/c++draft/lex.name#3.2, identifiers like
_foo are rerversed at global namespace. The macro BOOST_SCOPE_FINAL
(https://github.com/Lastique/scope/blob/develop/include/boost/scope/scope_fin...)
expands to something beginning with _boost_scope_final_. I don't think
that anyone would ever use BOOST_SCOPE_FINAL at global namespace, but
if they would, this would be a violation of lex.name#3.2
3. unique_resource seems interesting, one thing that might be missing
from this kind of scope based resource management would be a
shared_resource. In OpenCL, resources are internally reference
counted, and have the following functions
clCreate* which returns a new resource (eg clCreateBuffer)
clRetain* which increments an internal reference counter (eg clRetainMemObject)
clRelease* which decrements the internal reference counter (eg
clReleaseMemObject)
The following types meet this format: cl_mem, cl_event, cl_sampler,
cl_context, cl_command_queue, cl_device, and probably a few others.
Its fairly straightforward to crack these into a general type that
implements shared RAII semantics on top of these. Notably there's no
(sane) way to ever query the reference count of an object
пт, 24 нояб. 2023 г. в 23:58, Дмитрий Архипов
Dear Boost community. The peer review of the proposed Boost.Scope will start on 26th of November and continue until December 5th. Boost.Scope is a small library implementing utilities defined in
from C++ Extensions for Library Fundamentals v3 with a few extensions. Namely, the library contains: * A number of scope guards for various use cases. * A unique resource wrapper that automatically frees the resource on destruction. * Utilities for wrapping POSIX-like file descriptors in the unique resource wrapper. You can find the source code of the library at https://github.com/Lastique/scope and read the documentation at https://lastique.github.io/scope/libs/scope/doc/html/index.html. The library is header-only and thus it is fairly easy to try it out. In addition, the library can be used with Conan and vcpkg (see its README for instructions on how to do that). Finally, there's a single header version suitable for Compiler Explorer (https://raw.githubusercontent.com/Lastique/scope/single-header/include/boost...).
As the library is not domain-specific, everyone is very welcome to contribute a review either by sending it to the Boost mailing list, or me personally. In your review please state whether you recommend to reject or accept the library into Boost, and whether you suggest any conditions for acceptance.
Thanks in advance for your time and effort!
Dmitry Arkhipov, Staff Engineer at The C++ Alliance.
On 11/26/23 20:08, Дмитрий Архипов via Boost wrote:
I have also posted review announcements on Reddit and in Cpplang Slack workspace. Here are some comments I've received:
1. Given void f();
int main() { auto a = boost::scope::make_scope_fail(f); boost::scope::scope_fail b(f); } Only the declaration of b compiles. The one of a fails. I think the one of a should compile, too. Something like std::decay instead of typename std::remove_cv< typename std::remove_reference< F >::type
::type at https://github.com/Lastique/scope/blob/develop/include/boost/scope/scope_exi...
Will fix, thanks for letting me know. https://github.com/Lastique/scope/issues/6
2. According to http://eel.is/c++draft/lex.name#3.2, identifiers like _foo are rerversed at global namespace. The macro BOOST_SCOPE_FINAL (https://github.com/Lastique/scope/blob/develop/include/boost/scope/scope_fin...) expands to something beginning with _boost_scope_final_. I don't think that anyone would ever use BOOST_SCOPE_FINAL at global namespace, but if they would, this would be a violation of lex.name#3.2
The identifier prefix is chosen this way to avoid scope guards popping up in autocompletion in various IDEs. The prefix is pretty well qualified, so it is unlikely to clash with anything, even in the unlikely case if someone uses it at namespace scope. I'd prefer to keep it the way it is, unless it causes real problems to someone.
3. unique_resource seems interesting, one thing that might be missing from this kind of scope based resource management would be a shared_resource. In OpenCL, resources are internally reference counted, and have the following functions
clCreate* which returns a new resource (eg clCreateBuffer) clRetain* which increments an internal reference counter (eg clRetainMemObject) clRelease* which decrements the internal reference counter (eg clReleaseMemObject)
The following types meet this format: cl_mem, cl_event, cl_sampler, cl_context, cl_command_queue, cl_device, and probably a few others. Its fairly straightforward to crack these into a general type that implements shared RAII semantics on top of these. Notably there's no (sane) way to ever query the reference count of an object
I did think about shared_resource at some point, but couldn't decide on
the design. Possibly because I currently don't have a use case for it.
My main questions were:
- What to do with resource traits? Should those be exposed in the
shared_resource type? My gut feeling says "yes" as the traits are needed
to be able to tell whether the resource is allocated.
- How to make `reset()` non-throwing? Presumably, one should be able to
call `get()` on a shared_resource that is not in allocated state, and it
should return a reference to a resource object in a deallocated state
(e.g. -1 for an fd). Which means `reset()` may need to allocate memory
or something to create the resource object in that state.
The question above also adds reference counting into this list - should
shared_resource support custom reference counting policies?
In any case, I currently don't have answers to those questions, and
therefore not proposing a shared_resource. It may be added later, when
the answers are more clear. In the meantime, it is always possible to
use `shared_ptr
On 11/24/23 23:58, Дмитрий Архипов via Boost wrote:
Dear Boost community. The peer review of the proposed Boost.Scope will start on 26th of November and continue until December 5th. Boost.Scope is a small library implementing utilities defined in
from C++ Extensions for Library Fundamentals v3 with a few extensions. Namely, the library contains: * A number of scope guards for various use cases. * A unique resource wrapper that automatically frees the resource on destruction. * Utilities for wrapping POSIX-like file descriptors in the unique resource wrapper. You can find the source code of the library at https://github.com/Lastique/scope and read the documentation at https://lastique.github.io/scope/libs/scope/doc/html/index.html. The library is header-only and thus it is fairly easy to try it out. In addition, the library can be used with Conan and vcpkg (see its README for instructions on how to do that). Finally, there's a single header version suitable for Compiler Explorer (https://raw.githubusercontent.com/Lastique/scope/single-header/include/boost...).
I should add that the library source code that is submitted for the review is tagged boost-review-2023-11-26. That is, the review version of the code can be accessed at: https://github.com/Lastique/scope/tree/boost-review-2023-11-26 There are develop and master branches as well. The code in develop may be modified during the review.
As the library is not domain-specific, everyone is very welcome to contribute a review either by sending it to the Boost mailing list, or me personally. In your review please state whether you recommend to reject or accept the library into Boost, and whether you suggest any conditions for acceptance.
Thanks in advance for your time and effort!
Dmitry Arkhipov, Staff Engineer at The C++ Alliance.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Here's my review of boost.scope.
The library should be ACCEPTED without conditions.
I have myself written a boost.ScopeExit replacement for a private
project quite similar to scope_exit.
The reason is not only avoiding the dynamic allocation, but also that
the unwind code can be inline, allowing optimizations.
The scope_fail and scope_success looked a bit odd to me at first,
until I realized that having different types here allows for C++17
deduction guides. So that's a good choice.
All details, like the handling of exceptions from the exit handlers,
are implemented correctly & the code is very readable.
Movable scope guards can also come in very handy with boost asio, when
writing composed operations.
The unique_resource is great. I've been abusing std::unique_ptr quite
often to emulate this.
One thing to point out: boost.ScopeExit has the BOOST_SCOPE_EXIT_ALL
macro, that works like this:
BOOST_SCOPE_EXIT_ALL(this) { do_things(); }
boost.scope could have the BOOST_SCOPE_FINAL be compatible with this,
so that adoption would be a super simple search & replace.
The BOOST_SCOPE_FINAL is limited to C++17 because the correct way is
to use deduction guides, and that would be perfectly fine for me.
However, it would be quite simple to add this functionality to C++11 like so:
struct no_one_likes_expression_templates
{
template<typename Func>
auto operator%(Func && func) ->
decltype(boost::scope::make_scope_exit(std::declval<Func>()))
{
return boost::scope::make_scope_exit(std::forward<Func>(func));
}
};
#define BOOST_SCOPE_FINAL_11 \
auto BOOST_JOIN(_boost_scope_final_,
BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG) =
no_one_likes_expression_templates{} %
I spent about an hour reading the docs, the code and writing a small
toy program.
On Sat, Nov 25, 2023 at 4:58 AM Дмитрий Архипов via Boost
Dear Boost community. The peer review of the proposed Boost.Scope will start on 26th of November and continue until December 5th. Boost.Scope is a small library implementing utilities defined in
from C++ Extensions for Library Fundamentals v3 with a few extensions. Namely, the library contains: * A number of scope guards for various use cases. * A unique resource wrapper that automatically frees the resource on destruction. * Utilities for wrapping POSIX-like file descriptors in the unique resource wrapper. You can find the source code of the library at https://github.com/Lastique/scope and read the documentation at https://lastique.github.io/scope/libs/scope/doc/html/index.html. The library is header-only and thus it is fairly easy to try it out. In addition, the library can be used with Conan and vcpkg (see its README for instructions on how to do that). Finally, there's a single header version suitable for Compiler Explorer (https://raw.githubusercontent.com/Lastique/scope/single-header/include/boost...).
As the library is not domain-specific, everyone is very welcome to contribute a review either by sending it to the Boost mailing list, or me personally. In your review please state whether you recommend to reject or accept the library into Boost, and whether you suggest any conditions for acceptance.
Thanks in advance for your time and effort!
Dmitry Arkhipov, Staff Engineer at The C++ Alliance.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On 11/27/23 04:50, Klemens Morgenstern via Boost wrote:
The BOOST_SCOPE_FINAL is limited to C++17 because the correct way is to use deduction guides, and that would be perfectly fine for me. However, it would be quite simple to add this functionality to C++11 like so:
struct no_one_likes_expression_templates { template<typename Func> auto operator%(Func && func) -> decltype(boost::scope::make_scope_exit(std::declval<Func>())) { return boost::scope::make_scope_exit(std::forward<Func>(func)); } };
#define BOOST_SCOPE_FINAL_11 \ auto BOOST_JOIN(_boost_scope_final_, BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG) = no_one_likes_expression_templates{} %
This would be a misnomer as it would create a scope_exit instead of scope_final. You can't create a scope_final this way because it isn't moveable, and RVO is optional in C++11. I can provide C++11 macros a-la BOOST_SCOPE_FINAL for creating scope_exit/fail/success (e.g. BOOST_SCOPE_EXIT/FAIL/SUCCESS_GUARD), but I don't see a way to make BOOST_SCOPE_FINAL C++11.
On Mon, Nov 27, 2023 at 12:42 AM Andrey Semashev via Boost
...
Andrey: 1. Which experts were consulted during the development of this library (for example, did Peter Dimov offer any input)? 2. Are you in the C++ Language Slack Workspace ("cpplang")? 3. Which individuals contributed to reviewing the library as it was developed? 4. Who has tried to integrate Scope into their own code, before the review period? Thanks
On 11/28/23 18:25, Vinnie Falco wrote:
On Mon, Nov 27, 2023 at 12:42 AM Andrey Semashev via Boost
wrote: ...
Andrey:
1. Which experts were consulted during the development of this library (for example, did Peter Dimov offer any input)?
None beyond this list. Peter did offer his comments before the review. For example, I incorporated his suggestion to effectively rename scope_check to scope_exit. There were also notable comments from Andrzej Krzemienski and Klemens Morgenstern. Andrzej's comments allowed to improve the library docs and Klemens' suggestion to support error codes in scope_success/fail was incorporated into the library. You can find the discussions on this list by searching "[scope]" in the message title.
2. Are you in the C++ Language Slack Workspace ("cpplang")?
No.
3. Which individuals contributed to reviewing the library as it was developed?
I did not do an off-list review.
4. Who has tried to integrate Scope into their own code, before the review period?
I did. I'm not aware of other integrations, although the library is public for a little less than a year.
On Tue, 28 Nov 2023, 16:26 Vinnie Falco via Boost,
On Mon, Nov 27, 2023 at 12:42 AM Andrey Semashev via Boost
wrote: ...
Andrey:
1. Which experts were consulted during the development of this library (for example, did Peter Dimov offer any input)?
2. Are you in the C++ Language Slack Workspace ("cpplang")?
3. Which individuals contributed to reviewing the library as it was developed?
Since you seem pretty eager to ask opinionated questions, what do these three points have to do - if anything at all - with the quality of the library? Asking as a potential user. .Andrea
On Tue, Nov 28, 2023 at 9:45 AM Andrea Bocci via Boost < boost@lists.boost.org> wrote:
On Tue, 28 Nov 2023, 16:26 Vinnie Falco via Boost,
wrote: On Mon, Nov 27, 2023 at 12:42 AM Andrey Semashev via Boost
wrote: ...
Andrey:
1. Which experts were consulted during the development of this library (for example, did Peter Dimov offer any input)?
2. Are you in the C++ Language Slack Workspace ("cpplang")?
3. Which individuals contributed to reviewing the library as it was developed?
Since you seem pretty eager to ask opinionated questions, what do these three points have to do - if anything at all - with the quality of the library?
Asking as a potential user.
.Andrea
Not an answer to your question to Vinnie, but perhaps to set context -- the general shape of this library has been reviewed and discussed by many c++ experts. The Introduction section of the docs should really have a link to the reference below which provides deep motivation and discussion. Unfortunately just pointing at the 'Technical Specification' just shows the result and not the details that led to it. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0052r10.pdf I'd also mention there's a high likelihood of this facility being proposed for the standard either in 26 or 29. Jeff
On 11/28/23 19:58, Jeff Garland via Boost wrote:
The Introduction section of the docs should really have a link to the reference below which provides deep motivation and discussion. Unfortunately just pointing at the 'Technical Specification' just shows the result and not the details that led to it.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0052r10.pdf
Thanks for the link to the proposal, I've added it to the library docs.
On Tue, Nov 28, 2023 at 10:45 AM Andrey Semashev via Boost < boost@lists.boost.org> wrote:
On 11/28/23 19:58, Jeff Garland via Boost wrote:
The Introduction section of the docs should really have a link to the reference below which provides deep motivation and discussion. Unfortunately just pointing at the 'Technical Specification' just shows
the
result and not the details that led to it.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0052r10.pdf
Thanks for the link to the proposal, I've added it to the library docs.
Awesome -- thanks!
On Tue, Nov 28, 2023 at 10:45 AM Andrey Semashev via Boost < boost@lists.boost.org> wrote:
On 11/28/23 19:58, Jeff Garland via Boost wrote:
The Introduction section of the docs should really have a link to the reference below which provides deep motivation and discussion. Unfortunately just pointing at the 'Technical Specification' just shows
the
result and not the details that led to it.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0052r10.pdf
Thanks for the link to the proposal, I've added it to the library docs.
Maybe another thought would be to have a section that actually describes the extensions from the TS proposal (like the boost scoped exit compare) -- or did I miss it in the docs? My quick comparison looks to be mostly the fd_deleter and unique_fd stuff and not so much in the core api? Which are pure extensions and could be clearly marked as such -- and could later be converted to work with std::scope_* if people wanted? And fyi -- if you're not aware of this improvement it's already in 26 working paper and gcc 14: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p1759r6.html That might be motivation for including something like unique_fd at the standard level as well. Jeff
On 11/28/23 21:09, Jeff Garland via Boost wrote:
Maybe another thought would be to have a section that actually describes the extensions from the TS proposal (like the boost scoped exit compare) -- or did I miss it in the docs? My quick comparison looks to be mostly the fd_deleter and unique_fd stuff and not so much in the core api? Which are pure extensions and could be clearly marked as such -- and could later be converted to work with std::scope_* if people wanted?
Yes, this has already been requested and answered; I will add a section in the docs. https://github.com/Lastique/scope/issues/5 In the meantime, I'll reproduce the list of extensions below: * A new scope_final scope guard, which is a more lightweight alternative to scope_exit. It is accompanied with the BOOST_SCOPE_FINAL macro that allows to simplify scope guard declaration syntax. * Scope guards can be activated/deactivated multiple times. * Scope guards can be created inactive initially. * Scope guard factory functions, for compatibility with C++11. * Support for custom condition functions for checking scope guards. This, for example, allows one to check for error codes instead of exceptions in scope_fail/scope_success. * Support for optional resource traits in unique_resource wrapper, which improves usage with resources having unallocated values. * unique_resource supports swapping. * unique_resource supports dereferencing for any resource types that support dereferencing, not only pointers. * More flexible constructors for unique_resource.
On Tue, Nov 28, 2023 at 8:45 AM Andrea Bocci
Since you seem pretty eager to ask opinionated questions, what do these three points have to do - if anything at all - with the quality of the library?
I'm evaluating the author's library development hygiene. A formal review is as much about reviewing the author as it is about reviewing the library. For example, the very last thing we want is for an author to have a library accepted, and they promptly abandon the library with no support. This is a contrived example, I'm not saying it applies to this author, but I have seen cases where people just cook up a library with no support and hastily expel it onto the mailing list for a review. Andrey is a good Boost author with many contributions so this is sort of a formality. From now on I will be asking these questions of any author submitting a library for a review. The questions also serve as a subtle hint: if you are writing a library with the goal of submitting for a review, doing these things can't hurt and they can only possibly help: 1. Ask Peter Dimov to weigh in on the library 2. Consult other talented engineers regularly to help shape the public interface 3. Join the C++ Language Slack Workspace for enrichment and collaboration 4. Find stakeholders ahead of the review who would benefit from your library, and are willing to integrate it into their code to provide feedback There is also another benefit to collaborating with others during development: you can tap in to experts to get help on important areas such as documentation toolchains, cmake integration, continuous integration (per-commit testing), code coverage, and writing comprehensive tests. Thanks
Thanks for the clarification. This, on top of many of the previous comments I have seen on this mailing list, have made it clear that Boost is *not* the kind of environment where I want to submit the libraries I am writing. .Andrea
Andrea Bocci wrote:
Thanks for the clarification.
This, on top of many of the previous comments I have seen on this mailing list, have made it clear that Boost is *not* the kind of environment where I want to submit the libraries I am writing.
That is unfortunate. You should know that Vinnie is just one voice here among many. He can ask whatever he likes during a formal review, for the purpose of determining whether to cast his vote for acceptance or not, but does not speak for the Boost community. In particular, there is definitely no requirement for any prospective authors to have consulted me beforehand.
On Tue, Nov 28, 2023 at 11:44 AM Peter Dimov via Boost < boost@lists.boost.org> wrote:
Andrea Bocci wrote:
Thanks for the clarification.
This, on top of many of the previous comments I have seen on this mailing list, have made it clear that Boost is *not* the kind of environment where I want to submit the libraries I am writing.
That is unfortunate.
Very much agree.
You should know that Vinnie is just one voice here among many. He can ask whatever he likes during a formal review, for the purpose of determining whether to cast his vote for acceptance or not, but does not speak for the Boost community.
In particular, there is definitely no requirement for any prospective authors to have consulted me beforehand.
Or anyone else for that matter. The amazing thing is many very expert developers here are happy to lend a hand. Jeff
On Tue, Nov 28, 2023 at 9:39 AM Vinnie Falco
1. Ask Peter Dimov to weigh in on the library
To clarify this point, I use "Peter Dimov" only as an example. This is in no way to imply that Peter is a gatekeeper or "the CEO of Boost" or any such thing. It is a bit of inside humor which requires some understanding of the history of Boost to get. It just means that I greatly respect his opinions on many developmental subjects. Thanks
On 11/28/23 9:39 AM, Vinnie Falco via Boost wrote:
On Tue, Nov 28, 2023 at 8:45 AM Andrea Bocci
wrote:
1. Ask Peter Dimov to weigh in on the library 2. Consult other talented engineers regularly to help shape the public interface 3. Join the C++ Language Slack Workspace for enrichment and collaboration 4. Find stakeholders ahead of the review who would benefit from your library, and are willing to integrate it into their code to provide feedback
There is also another benefit to collaborating with others during development: you can tap in to experts to get help on important areas such as documentation toolchains, cmake integration, continuous integration (per-commit testing), code coverage, and writing comprehensive tests.
FWIW. The Boost Library Incubator accepted Boost Library proposals long in advance of any formal review. This permmited users and potential users to consider the early version of the library. It also permitted anyone to submit a formal review in advance of the scheduling of any formal review. The idea was to encourage people to try out the library, give feed back, perhaps use the library and prepare a formal review when they had the time in the understanding that their formal review would be considered when the time came. One motivation was to increase the number of reviews submitted. But all the above goals would also be served. Although I thought it was a good idea addressing real issues, it failed to get the traction I hoped for it. Maintaining the web pages (in PHP) was also a major pain. Just one more failure in my life. Oh well. Robert Ramey
On Tue, Nov 28, 2023 at 3:35 PM Robert Ramey via Boost < boost@lists.boost.org> wrote:
FWIW. The Boost Library Incubator accepted Boost Library proposals long in advance of any formal review.
..
Although I thought it was a good idea addressing real issues, it failed to get the traction I hoped for it. Maintaining the web pages (in PHP) was also a major pain. Just one more failure in my life. Oh well.
FWIW I think the idea still has merit. But it might need to 'come with teeth' - like you're not in Boost without going into the incubator first. And maybe it should be more than some repos -- like an actual distribution that could overlay a boost release with the libraries that are part of the incubator. It should be included in the test infrastructure to demonstrate (or not) the metal of the library. Think of it like std::experimental -- it's boost::experimental basically. The other aspect I liked was the mentoring of new authors -- we really need more of that.
PHP...major pain
yes, it should be retooled to rid us of PHP madness... Jeff
On 11/28/23 4:54 PM, Jeff Garland via Boost wrote:
On Tue, Nov 28, 2023 at 3:35 PM Robert Ramey via Boost < boost@lists.boost.org> wrote:
FWIW. The Boost Library Incubator accepted Boost Library proposals long in advance of any formal review.
..
Although I thought it was a good idea addressing real issues, it failed to get the traction I hoped for it. Maintaining the web pages (in PHP) was also a major pain. Just one more failure in my life. Oh well.
FWIW I think the idea still has merit. But it might need to 'come with teeth' - like you're not in Boost without going into the incubator first.
I hoped that things would evolve to that point. But it needed to be sold first - hence the version I made.
And maybe it should be more than some repos -- like an actual distribution that could overlay a boost release with the libraries that are part of the incubator.
This conflicts with my vision of a "modular" boost. I would hope that if our norms about boost rules were a little more formal (Concepts) we could create libraries which didn't have to be part of boost to function. The we could just a a library at will and be on our way. This would work for nich libraries and questionable libraries like those in the incubator. The library could be dropped just by deleting it. This seems like it should be possible since no other library will depend on the inclubator/nitch library. Maybe were already there. But our build/test/documentation infrastructure doesn't encourage this type of modularity. It turns out that many/most of the submissions were not even close to boost quality. And those that were, didn't really require the incubator to get accepted. It also required altering the test/build/documentation infrastructure to work well. That is, it sort of required that "modular boost" be more of a reality than it currently is. It should be included in the test infrastructure to demonstrate
(or not) the metal of the library. Think of it like std::experimental -- it's boost::experimental basically. The other aspect I liked was the mentoring of new authors -- we really need more of that.
Yep - all of that.
PHP...major pain
yes, it should be retooled to rid us of PHP madness...
Jeff
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On Wed, Nov 29, 2023 at 2:56 PM Robert Ramey via Boost < boost@lists.boost.org> wrote:
On 11/28/23 4:54 PM, Jeff Garland via Boost wrote:
On Tue, Nov 28, 2023 at 3:35 PM Robert Ramey via Boost < boost@lists.boost.org> wrote:
And maybe it should be more than some repos -- like an actual distribution that could overlay a boost release with the libraries that are part of the incubator.
This conflicts with my vision of a "modular" boost. I would hope that if our norms about boost rules were a little more formal (Concepts) we could create libraries which didn't have to be part of boost to function. The we could just a a library at will and be on our way. This would work for nich libraries and questionable libraries like those in the incubator. The library could be dropped just by deleting it. This seems like it should be possible since no other library will depend on the inclubator/nitch library. Maybe were already there. But our build/test/documentation infrastructure doesn't encourage this type of modularity.
I think we can do both -- we can distribute collections while encouraging modular libraries that can be used on their own. I think in most cases that might still mean a tie back to boost.core, but that's small.
It turns out that many/most of the submissions were not even close to boost quality. And those that were, didn't really require the incubator to get accepted. It also required altering the test/build/documentation infrastructure to work well. That is, it sort of required that "modular boost" be more of a reality than it currently is.
Interesting -- it's almost as if the authors that are gonna succeed in boost can cut thru everything by themselves. Jeff
On Fri, 24 Nov 2023 at 21:58, Дмитрий Архипов via Boost < boost@lists.boost.org> wrote:
Dear Boost community. The peer review of the proposed Boost.Scope will start on 26th of November and continue until December 5th. Boost.Scope is a small library implementing utilities defined in
from C++ Extensions for Library Fundamentals v3 with a few extensions. Namely, the library contains: * A number of scope guards for various use cases. * A unique resource wrapper that automatically frees the resource on destruction. * Utilities for wrapping POSIX-like file descriptors in the unique resource wrapper. You can find the source code of the library at https://github.com/Lastique/scope and read the documentation at https://lastique.github.io/scope/libs/scope/doc/html/index.html. The library is header-only and thus it is fairly easy to try it out. In addition, the library can be used with Conan and vcpkg (see its README for instructions on how to do that). Finally, there's a single header version suitable for Compiler Explorer ( https://raw.githubusercontent.com/Lastique/scope/single-header/include/boost... ).
Very nice little library, thank you. Complete and easy to understand. I will certainly use it if it makes it into Boost.
As the library is not domain-specific, everyone is very welcome to contribute a review either by sending it to the Boost mailing list, or me personally. In your review please state whether you recommend to reject or accept the library into Boost, and whether you suggest any conditions for acceptance.
Thanks in advance for your time and effort!
Dmitry Arkhipov, Staff Engineer at The C++ Alliance.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
A few more comments from Reddit
#1, a min-review:
1. It's rather telling that scope guards and descriptor/resources
headers are mutually independent. This library should be split into
two.
2. Why do you dispatch between std/boost type traits? Why not always
use boost ones (which I assume already dispatch to std internally when
possible)?
I recommend acceptance assuming the above points are addressed.
#2, a code review:
1. Hard complaint about wrappers around basic type traits like
std::conjunction. That's a terrible anti-pattern. Just depend on the
version of C++ that has the features you need. This is how most of the
libs in boost depend (or did until very recently) on C++03, and as a
result use macro-preprocessor hacks to implement variadic templates.
If you really need to do things this way for some reason, then
implement a deprecation policy that you'll stick to for when you'll
remove these wrappers.
2. I'm not a fan of include/boost/scope/detail/header.hpp Suppressing
warnings instead of fixing them (Unless the warnings are determined by
the author to be caused by a compiler bug, which i've had happen
before) should be the last approach taken.
3. #ifdef BOOST_HAS_PRAGMA_ONCE : why bother? you have a normal
include guard. What does this do for you? The major compilers use the
same code paths for pragma once as they do for include guards, or so i
read on some blog that seemed authoratitve a long time ago.
4. include/boost/scope/detail/move_or_copy_construct_ref.hpp the _t
version of type traits are frequently less expensive for the compiler
instantiate than the struct version. I recommend flipping these so
that the struct version of the type-trait is derived from the _t
version.
5. I see the frequent use of typedef. Why? Are you trying to support
C++03? I strongly recommend against supporting C++03. Use using
instead.
6. include/boost/scope/detail/is_not_like.hpp: no human readable
explanation of what this type-trait is supposed to do.
7. include/boost/scope/detail/compact_storage.hpp : surely this should
live in https://www.boost.org/doc/libs/1_83_0/libs/utility/doc/html/utility/utilitie...
and not in scope ?
8. include/boost/scope/detail/compact_storage.hpp: If you're going to
change the implementation of things based on which version of C++ is
being compiled with (e.g. the type traits stuff), you might as well
provide an implementation of this with [[no_unique_address]].
9. include/boost/scope/detail/compact_storage.hpp: More explanation in
the class implementation of how it works and why would be helpful for
future readers.
10. include/boost/scope/detail/compact_storage.hpp: Instead of get()
member functions, what about implicit conversion operators instead?
11. include/boost/scope/unique_resource.hpp: Can't you use
boost::is_nothrow_invocable<> for the ref_wrapper::operator() noexcept
specification?
12. include/boost/scope/unique_resource.hpp: What does ref_wrapper buy
you that std::reference_wrapper doesn't? Whatever that is, document it
in the code.
13. include/boost/scope/unique_resource.hpp : resource_holder::get()
functions. Why not use using resource_base::get; instead? More
compact.
14. detail::move_or_copy_construct_ref: so far everywhere i've seen
this used, simply replacing it with std::move() would have worked just
as well. Why use the type-trait?
15. unique_resource_data::swap_impl: std::swap(m_allocated, that.allocated);
16. static_cast< unique_resource_data&& >(that) : std::move() by any other name?
17. unique_resource.hpp: "An lvalue reference to an object type." Why
would someone want to do this? Seems like an easy way to foot-gun
oneself.
18. unique_resource.hpp: "The deleter must be copy-constructible."
Perhaps discuss whether move-constructible matters at all.
19. unique_resource.hpp: "One of the unallocated resource values can
be considered the default. Constructing the default resource value and
assigning it to a resource object (whether allocated or not) shall not
throw exceptions." What is enforcing this requirement?
20. "// Workaround for clang < 5.0 which can't pass scope_success as a
template template parameter from within scope_success definition" Why
support such an old compiler?
21. include/boost/scope/scope_success.hpp: logical_not: is this not
just std::not_fn ? Previous to C++17, std::not1. Why implement this
yourself?
22. "Scope exit guard that invokes a function upon leaving the scope
with a failure condition not satisfied." Awkward wording.
23. "Additionally, the failure condition function object operator()
must not throw," where is this enforced?
24. explicit scope_success(F&& func, C&& cond, bool active = true)
can't you take the class-level template parameters by value, and rely
on implicit conversion of the provided arguments ? That would reduce
template instantiations substantially.
25. include/boost/scope/scope_success.hpp: I'm wary of the factory
functions like make_scope_success. This seems like an anti-pattern
that's only implemented because prior versions of C++ don't have the
needed expressiveness, like deduction guides.
26. include/boost/scope/error_code_checker.hpp Why store the error
code by pointer, and not by normal lvalue-reference (const, even) ?
27. A general comment about the implementation, i don't like how many
places use std::enable_if. This is an immense compile-time slowdown.
C++20 concepts appear to be much faster, but avoiding the
metaprogramming where practical is much desired. Maybe static_assert()
on various restrictions and simply don't provide fallbacks for things
that aren't satisfied. For example, is it really important to support
final classes? If not, you can cut your implementation by around
1/4th.
28. Table 1.1. Boost.ScopeExit and Boost.Scope syntax overview: why no
macro for the failure handler?
29. html/scope/scope_guards.html: "an lvalue reference to a function
taking no arguments.", can't give you a function pointer? it has to be
an lvalue-reference?
30. html/scope/scope_guards.html: "For this reason, action functions
that are used with scope_fail are typically not allowed to throw, as
this may cause the program to terminate." you aren't wrong, but why is
it boost.scope's job to enforce this?
31. Table 1.3. Comparison of scope_fail and scope_exit: Your examples
are confusing, because the vector would have already undone it's push
if the push threw an exception.
32. html/scope/unique_resource.html: IMHO I don't think
unique_resource belongs in this library. It doesn't appear to re-use
any of the code from the scope_*** family of objects, and seems more
appropriate to put into either the Boost.SmartPtr library, make a new
library for SmartResources, or SmartPtr, SmartResources, and Scope
should all go into a "Boost.Raii" library.
33. for set_active(), personally i'd rather have a enable() and
disable() (or whatever name) function so that I can take the address
of the member function as a parameterless function, and do things with
it that way. The need for that is infrequent, but it's served me well
in the past.
34. Should all scope guards be able to be activated / deactivated?
You'd save a lot of stack space for users if they had the ability to
opt-in to that ability instead of always having it.
After some persuasion, the second redditor has added a resolution,
turning his code review into a proper review:
Conditional reject:
* This library should not have multiple separate tools that don't
share a common theme. The resource management functionality is not
appropriate to mix into the same namespace as generic scope guard
stuff, and is more appropriately added to the SmartPtr library, or a
new SmartResources library.
* I strongly dislike the default-disablement of compiler warnings. I
have SO MANY patches on top of boost (which any time I've submitted
them as PRs to github have been rejected, so i stopped bothering years
ago) to squash all the warnings I get from boost, and I don't want
more of that. If your code isn't warning free without suppression
pragmas, it shouldn't be submitted to boost, with the only exception
being warnings that the compiler is producing erroneously, and the
suppression for those should be as narrowly scoped as possible with
justification put as a comment along side the pragma about why the
compiler can't be satisfied without the pragma
* Too many C++03-isms: Targeting C++11 does a major disservice to the
world. C++11 was released over a decade ago. Move forward. Target
C++14 at a minimum, but C++17 is ideal. I won't say to target C++20,
since that's not practical for most organizations at this time (given
compilers only recently, e.g. last 6 months, had viable
implementations of C++20 that didn't internal-compiler-error all over
the place). I won't say that targeting C++14/17 is a part of the
conditional rejection, but if you're going to target C++11, then use
C++11 functionality, like using.
* Where ever possible (e.g. supported by your targeted language
version), use the _t and _v version of type-traits over the
thing<>::value and thing<>::type version, otherwise you're forcing
your consumer's compilers to do notably more work.
That's a narrowly scoped list of 4 action items for my opinion to
change from reject to accept.
пт, 24 нояб. 2023 г. в 23:58, Дмитрий Архипов
Dear Boost community. The peer review of the proposed Boost.Scope will start on 26th of November and continue until December 5th. Boost.Scope is a small library implementing utilities defined in
from C++ Extensions for Library Fundamentals v3 with a few extensions. Namely, the library contains: * A number of scope guards for various use cases. * A unique resource wrapper that automatically frees the resource on destruction. * Utilities for wrapping POSIX-like file descriptors in the unique resource wrapper. You can find the source code of the library at https://github.com/Lastique/scope and read the documentation at https://lastique.github.io/scope/libs/scope/doc/html/index.html. The library is header-only and thus it is fairly easy to try it out. In addition, the library can be used with Conan and vcpkg (see its README for instructions on how to do that). Finally, there's a single header version suitable for Compiler Explorer (https://raw.githubusercontent.com/Lastique/scope/single-header/include/boost...).
As the library is not domain-specific, everyone is very welcome to contribute a review either by sending it to the Boost mailing list, or me personally. In your review please state whether you recommend to reject or accept the library into Boost, and whether you suggest any conditions for acceptance.
Thanks in advance for your time and effort!
Dmitry Arkhipov, Staff Engineer at The C++ Alliance.
One thing I've noticed is that several people do not think that scope
guards and unique_resource belong in the same library. I at first
found it curious, but then I've realised that the source of the issue
is that people associate the name "Scope" with scope guards
specifically. Maybe there's an argument for a different name?
чт, 30 нояб. 2023 г. в 12:29, Дмитрий Архипов
A few more comments from Reddit
On 11/30/23 12:34, Дмитрий Архипов via Boost wrote:
One thing I've noticed is that several people do not think that scope guards and unique_resource belong in the same library. I at first found it curious, but then I've realised that the source of the issue is that people associate the name "Scope" with scope guards specifically.
It's not unreasonable. I also feel that it is unfortunate that the TS defined unique_resource and scope guards in the same <scope> header. I think, unique_resource should have been defined in a header of its own. But then I also think that most standard library headers are excessively coarse grained. Boost.Scope mitigates this to a degree by defining every component in its own header, so at least users don't include what they don't need. Anyway, the reason why I'm bringing scope guards together with unique_resource in one library is because it is specified so in the TS. If the review result shows that the library should be split in two, I will be fine with that.
Maybe there's an argument for a different name?
If the problem is that scope guards and unique_resource are too unrelated, I don't think renaming the library solves it. And I wouldn't like naming the library somehow generic, like Boost.RAII, as was suggested by someone. I like the Boost.Scope name, at least with respect to scope guards part. If the library as currently proposed is deemed unacceptable because scope guards and unique_resource are too unrelated, and the choice is either rename or split in two, I would rather split and keep the Boost.Scope name for the part with scope guards.
On 11/30/23 12:29, Дмитрий Архипов via Boost wrote:
A few more comments from Reddit #1, a min-review:
1. It's rather telling that scope guards and descriptor/resources headers are mutually independent. This library should be split into two.
I'll reply separately.
2. Why do you dispatch between std/boost type traits? Why not always use boost ones (which I assume already dispatch to std internally when possible)?
Boost.TypeTraits do not use std type traits internally, at least not at this point. Boost.Scope uses std type traits that are available at the given C++ level with the compiler being used, and uses Boost.TypeTraits or self-implemented alternatives where the standard type traits are missing. In a conforming C++17 compiler, Boost.Scope should fully rely on std type traits.
#2, a code review: 1. Hard complaint about wrappers around basic type traits like std::conjunction. That's a terrible anti-pattern. Just depend on the version of C++ that has the features you need. This is how most of the libs in boost depend (or did until very recently) on C++03, and as a result use macro-preprocessor hacks to implement variadic templates. If you really need to do things this way for some reason, then implement a deprecation policy that you'll stick to for when you'll remove these wrappers.
I don't think requiring C++17 at the minimum (which is what is needed to fully rely on std type traits) is reasonable at this point in time. As the library maintainer, I have no problem using Boost.TypeTraits, where needed. If users do not want the library to use Boost.TypeTraits for some reason, they can simply use C++17 mode in their compilers.
2. I'm not a fan of include/boost/scope/detail/header.hpp Suppressing warnings instead of fixing them (Unless the warnings are determined by the author to be caused by a compiler bug, which i've had happen before) should be the last approach taken.
header.hpp disables warnings that I consider not useful. I will not be crippling the actual code trying to work around these warnings (where at all possible) as this would not improve the code quality, IMO. Note that the warnings are only disabled for the library code, as there is an accompanying footer.hpp that restores the warnings to the previous state. If you really want to enable the warnings for some reason, you can define BOOST_SCOPE_ENABLE_WARNINGS. No, it doesn't mean I will be fixing them in the library code, if you do. Also, and this relates to some further comments below, everything in detail is library implementation details and not intended for user consumption. Reviewing that code is fine and welcome, but keep in mind that these components are only as "polished" as needed for the library itself.
3. #ifdef BOOST_HAS_PRAGMA_ONCE : why bother?
Why not?
4. include/boost/scope/detail/move_or_copy_construct_ref.hpp the _t version of type traits are frequently less expensive for the compiler instantiate than the struct version. I recommend flipping these so that the struct version of the type-trait is derived from the _t version.
If you mean type aliases a-la std::remove_cv_t vs. std::remove_cv then no, the _t versions are not less expensive and are actually implemented through the structs. The _v type traits could potentially circumvent the structs and use compiler intrinsics directly, but I actually don't see this e.g. in libstdc++11. But anyway, variable templates and the _t versions of std type traits are C++14 and my target is C++11.
5. I see the frequent use of typedef. Why? Are you trying to support C++03? I strongly recommend against supporting C++03. Use using instead.
I don't see much difference between them, and I'm just used to typedef. I can change it if reviewers demand.
6. include/boost/scope/detail/is_not_like.hpp: no human readable explanation of what this type-trait is supposed to do.
It tests whether the left-hand type is not an instantiation of the right-hand template.
7. include/boost/scope/detail/compact_storage.hpp : surely this should live in https://www.boost.org/doc/libs/1_83_0/libs/utility/doc/html/utility/utilitie... and not in scope ?
Maybe. If there is demand, I may move that utility to some common place in the future.
8. include/boost/scope/detail/compact_storage.hpp: If you're going to change the implementation of things based on which version of C++ is being compiled with (e.g. the type traits stuff), you might as well provide an implementation of this with [[no_unique_address]].
I don't see the advantage of that, given that the current approach works. Is there a use case that would specifically benefit from [[no_unique_address]]?
9. include/boost/scope/detail/compact_storage.hpp: More explanation in the class implementation of how it works and why would be helpful for future readers.
This is an implementation detail. EBO is common knowledge at this point, I don't think there's much to explain.
10. include/boost/scope/detail/compact_storage.hpp: Instead of get() member functions, what about implicit conversion operators instead?
What would be the benefit of that? compact_storage is not intended to impersonate the type or act like it. It is exactly what the name says - a compact way to store the object.
11. include/boost/scope/unique_resource.hpp: Can't you use boost::is_nothrow_invocable<> for the ref_wrapper::operator() noexcept specification?
I've already changed that in develop. Originally, I think, that code was written before I introduced is_nothrow_invocable.
12. include/boost/scope/unique_resource.hpp: What does ref_wrapper buy you that std::reference_wrapper doesn't? Whatever that is, document it in the code.
I don't want to include <functional> just for std::reference_wrapper.
13. include/boost/scope/unique_resource.hpp : resource_holder::get() functions. Why not use using resource_base::get; instead? More compact.
I prefer to see the actual functions that I'm defining in the class.
14. detail::move_or_copy_construct_ref: so far everywhere i've seen this used, simply replacing it with std::move() would have worked just as well. Why use the type-trait?
move_or_copy_construct_ref is not equivalent to std::move. The latter would create an rvalue reference regardless of whether the move constructor is noexcept or not, and move_or_copy_construct_ref will produce an lvalue reference if the constructor is not noexcept. This ensures that the source object is not invalidated if the construction throws. This behavior is required by https://cplusplus.github.io/fundamentals-ts/v3.html#scopeguard.exit paragraph 7.11.
15. unique_resource_data::swap_impl: std::swap(m_allocated, that.allocated);
I don't want to include <algorithm> just for std::swap.
16. static_cast< unique_resource_data&& >(that) : std::move() by any other name?
I don't want to include <utility> just for std::move.
17. unique_resource.hpp: "An lvalue reference to an object type." Why would someone want to do this? Seems like an easy way to foot-gun oneself.
Personally, I don't have a practical use case for this, but I imagine it allows for non-copyable and non-moveable resource types. That's just what the TS supports, so Boost.Scope supports this as well.
18. unique_resource.hpp: "The deleter must be copy-constructible." Perhaps discuss whether move-constructible matters at all.
I'm not sure what you mean here. Copy-constructible implies move-constructible.
19. unique_resource.hpp: "One of the unallocated resource values can be considered the default. Constructing the default resource value and assigning it to a resource object (whether allocated or not) shall not throw exceptions." What is enforcing this requirement?
Nothing, this is a precondition. If it is not satisfied, unique_resource may not behave as expected.
20. "// Workaround for clang < 5.0 which can't pass scope_success as a template template parameter from within scope_success definition" Why support such an old compiler?
The workaround is simple enough, so why not?
21. include/boost/scope/scope_success.hpp: logical_not: is this not just std::not_fn ? Previous to C++17, std::not1. Why implement this yourself?
I don't want to include <functional> just for that trivial function object wrapper.
22. "Scope exit guard that invokes a function upon leaving the scope with a failure condition not satisfied." Awkward wording.
Thanks, I paraphrased the description. English is not my native language, so I would appreciate suggestions to improve the docs. Preferably, in the form of PRs.
23. "Additionally, the failure condition function object operator() must not throw," where is this enforced?
It is not enforced. I'm not enforcing it because this will effectively prohibit using raw functions as condition functions prior to C++17, which added noexcept to function types. I don't think it is worth enforcing in C++17 onwards either, as this would introduce incompatibility between different standard versions.
24. explicit scope_success(F&& func, C&& cond, bool active = true) can't you take the class-level template parameters by value, and rely on implicit conversion of the provided arguments ? That would reduce template instantiations substantially.
This would add an extra copy/move to initialize the scope guard members.
25. include/boost/scope/scope_success.hpp: I'm wary of the factory functions like make_scope_success. This seems like an anti-pattern that's only implemented because prior versions of C++ don't have the needed expressiveness, like deduction guides.
Right. Factory functions are there exactly to support C++11.
26. include/boost/scope/error_code_checker.hpp Why store the error code by pointer, and not by normal lvalue-reference (const, even) ?
Storing a pointer keeps the error_code_checker class assignable. Not that it should matter for scope guards, but still might be useful in some contexts.
27. A general comment about the implementation, i don't like how many places use std::enable_if. This is an immense compile-time slowdown. C++20 concepts appear to be much faster, but avoiding the metaprogramming where practical is much desired. Maybe static_assert() on various restrictions and simply don't provide fallbacks for things that aren't satisfied. For example, is it really important to support final classes? If not, you can cut your implementation by around 1/4th.
Concepts are C++20, so not acceptable for me. static_asserts are not a replacement for SFINAE. SFINAE is used specifically to avoid compilation errors and guide overload resolution where needed. With constructors and assignment, SFINAE plays its role with type traits that users (or even Boost.Scope code itself) may use to limit its downstream overloads. For example, you can see how scope guard factory functions test whether the respective scope guard can be constructed from the arguments.
28. Table 1.1. Boost.ScopeExit and Boost.Scope syntax overview: why no macro for the failure handler?
As answered to another reviewer, I didn't see enough motivation to provide macros for scope_exit/success/fail. Those scope guards are more likely to be interacted with after construction, and the construction itself is more elaborate, which doesn't work with syntax used by BOOST_SCOPE_FINAL.
29. html/scope/scope_guards.html: "an lvalue reference to a function taking no arguments.", can't give you a function pointer? it has to be an lvalue-reference?
I've updated the docs (and code) on develop to work with function pointers.
30. html/scope/scope_guards.html: "For this reason, action functions that are used with scope_fail are typically not allowed to throw, as this may cause the program to terminate." you aren't wrong, but why is it boost.scope's job to enforce this?
It doesn't enforce it. The discussion you quoted is just a recommendation to the user.
31. Table 1.3. Comparison of scope_fail and scope_exit: Your examples are confusing, because the vector would have already undone it's push if the push threw an exception.
There are two vectors. The scope guard reverts the push_back on the first if the second one throws.
32. html/scope/unique_resource.html: IMHO I don't think unique_resource belongs in this library. It doesn't appear to re-use any of the code from the scope_*** family of objects, and seems more appropriate to put into either the Boost.SmartPtr library, make a new library for SmartResources, or SmartPtr, SmartResources, and Scope should all go into a "Boost.Raii" library.
Will answer separately. Regarding the implementation, unique_resource does share some implementation bits with scope guards. Not that there is very much to share, but still.
33. for set_active(), personally i'd rather have a enable() and disable() (or whatever name) function so that I can take the address of the member function as a parameterless function, and do things with it that way. The need for that is infrequent, but it's served me well in the past.
As answered earlier, I strongly prefer a bool parameter to a pair of functions, because you sometimes receive that bool (or something similar) from elsewhere. In your case, you wouldn't be taking address of a function (which is a bad thing anyway, because the signature may change), but instead you would be keeping that bool.
34. Should all scope guards be able to be activated / deactivated? You'd save a lot of stack space for users if they had the ability to opt-in to that ability instead of always having it.
There is scope_final that doesn't support cancellation.
On 30.11.23 18:49, Andrey Semashev via Boost wrote:
On 11/30/23 12:29, Дмитрий Архипов via Boost wrote:
6. include/boost/scope/detail/is_not_like.hpp: no human readable explanation of what this type-trait is supposed to do.
It tests whether the left-hand type is not an instantiation of the right-hand template.
Have you considered inverting this test? I consider negative conditions in identifiers a code smell because they tend to lead to confusing double negatives. !is_like reads as clearly to me as is_not_like, but !is_not_like reads much worse than is_like. -- Rainer Deyke (rainerd@eldwood.com)
On 12/1/23 11:17, Rainer Deyke via Boost wrote:
On 30.11.23 18:49, Andrey Semashev via Boost wrote:
On 11/30/23 12:29, Дмитрий Архипов via Boost wrote:
6. include/boost/scope/detail/is_not_like.hpp: no human readable explanation of what this type-trait is supposed to do.
It tests whether the left-hand type is not an instantiation of the right-hand template.
Have you considered inverting this test? I consider negative conditions in identifiers a code smell because they tend to lead to confusing double negatives. !is_like reads as clearly to me as is_not_like, but !is_not_like reads much worse than is_like.
Everywhere in the library, it is needed to test that the type is *not* like the template. Making the type trait positive would require adding detail::negation wrapper, i.e. adding one more template instantiation.
Am 30.11.23 um 18:49 schrieb Andrey Semashev via Boost:
3. #ifdef BOOST_HAS_PRAGMA_ONCE : why bother? Why not? It is extra code without any benefit, isn't it?
6. include/boost/scope/detail/is_not_like.hpp: no human readable explanation of what this type-trait is supposed to do. It tests whether the left-hand type is not an instantiation of the right-hand template. I think the point was that this explanation should be in the file. I don't want to include <functional> just for std::reference_wrapper. I don't want to include <algorithm> just for std::swap. I don't want to include <utility> just for std::move. I don't want to include <functional> just for that trivial function object wrapper. I collected all such statements from your replies and would like to object: Reimplementing std-library components to avoid an include looks very wrong to me.
Not only is it likely premature optimization: User code including your
headers likely included those files already making the include "free".
Especially as many std-headers transitively include <utility> or even
<algorithm>.
And 2nd: With the collection above there are now 2 points obvious that
<functional> is not included "just for x" and then "just for y". So now
you have 2 reasons already to include it.
And finally this is about readability: Everyone knows what
`std::move(that)` does, but it is not that obvious for `static_cast<
unique_resource_data&& >(that)` Similar for swapping "m_allocated" being
expanded to 3 lines instead of `std::swap` obfuscating what it does. And
ref_wrapper begs the question if and how it is different to
std::reference_wrapper
TLDR: I'd strongly suggest to use the std-library where possible to a)
not reinvent the wheel and b) improve readability by using existing
idioms/names.
And a possible bug I've just seen: template< typename R, typename D,...>
explicit unique_resource_data(R&& res, D&& del)... :
unique_resource_data(static_cast< R&& >(res), static_cast< D&& >(del),
traits_type::is_allocated(static_cast< R&& >(res))) { }
The `static_cast
On 12/1/23 11:32, Alexander Grund via Boost wrote:
Am 30.11.23 um 18:49 schrieb Andrey Semashev via Boost:
3. #ifdef BOOST_HAS_PRAGMA_ONCE : why bother? Why not? It is extra code without any benefit, isn't it?
Whether there is any benefit depends on the compiler implementation. It doesn't cost me much to add three lines per header, if it may improve compile speeds in some cases. I don't feel strongly enough about this, so if there are objections from the users or reviewers, I can remove them. I just don't see the reason to.
6. include/boost/scope/detail/is_not_like.hpp: no human readable explanation of what this type-trait is supposed to do. It tests whether the left-hand type is not an instantiation of the right-hand template. I think the point was that this explanation should be in the file.
I can add a comment, but I reiterate that this is an implementation detail.
I don't want to include <functional> just for std::reference_wrapper. I don't want to include <algorithm> just for std::swap. I don't want to include <utility> just for std::move. I don't want to include <functional> just for that trivial function object wrapper. I collected all such statements from your replies and would like to object: Reimplementing std-library components to avoid an include looks very wrong to me.
Not only is it likely premature optimization: User code including your headers likely included those files already making the include "free".
This depends on user's code. I have use cases where scope guards are
used in very lightweight public headers (where functions are inline for
performance reasons), so every included header matters.
To put it another way, Boost.Scope header includes set the lowest bar of
dependencies that the user's code can have. I see value in setting that
bar as low as possible, without having to add unreasonable amount of
code duplication. That's why I'm including
Especially as many std-headers transitively include <utility> or even <algorithm>.
That would be a QoI matter. Most standard libraries include more fine-grained private headers internally to only pull the components they need for the purpose of the public headers.
And 2nd: With the collection above there are now 2 points obvious that <functional> is not included "just for x" and then "just for y". So now you have 2 reasons already to include it.
Those two instances are in different and unrelated headers. Specifically, in scope_success.hpp I need a negation function object, and in unique_resource.hpp I need a lightweight reference wrapper. In the latter case, not even full reference_wrapper, but something that will just invoke operator() on a pointer. Frankly, when I wrote that code I was considering using boost::reference_wrapper instead. But unfortunately it doesn't support operator(), and also includes extra bells and whistles that I don't need, so I just decided to write a simple wrapper myself. If it had operator(), I would probably use boost::reference_wrapper.
And finally this is about readability: Everyone knows what `std::move(that)` does, but it is not that obvious for `static_cast< unique_resource_data&& >(that)` Similar for swapping "m_allocated" being expanded to 3 lines instead of `std::swap` obfuscating what it does. And ref_wrapper begs the question if and how it is different to std::reference_wrapper
I'm willing to exchange some amount of readability for potentially improving compile times. As the maintainer, I think, I'm allowed to make that tradeoff.
TLDR: I'd strongly suggest to use the std-library where possible to a) not reinvent the wheel and b) improve readability by using existing idioms/names.
An a general comment regarding the use (or not use) of the standard library. I do not consider the standard library a holy cow of some sort, and I will not use its components just because it's standard library. I have said it before, and I'll reiterate that I will consider my options before using another library, including the standard library. One of these options is implementing the component myself, and sometimes, this option is the most appealing. I'm not going to disregard that option "just because".
And a possible bug I've just seen: template< typename R, typename D,...> explicit unique_resource_data(R&& res, D&& del)... : unique_resource_data(static_cast< R&& >(res), static_cast< D&& >(del), traits_type::is_allocated(static_cast< R&& >(res))) { }
The `static_cast
` look wrong. Should that be a std::move or std::forward? It is std::forward, but I had to check to be sure. (see above where a similar cast was a std::move) To me it looks like it`is_allocated` should not have a cast, should it? What if it is implemented to accept an instance, you castit to an rvalue, i.e. move it into that call and then use the moved-from value to construct `unique_resource_data` Similar for the deleter where using std::forward makes the intent clear.
Thanks, I will take a look at that code. Quite possibly you're right, and I should avoid forwarding to is_allocated.
On 12/1/23 15:26, Andrey Semashev wrote:
On 12/1/23 11:32, Alexander Grund via Boost wrote:
And a possible bug I've just seen: template< typename R, typename D,...> explicit unique_resource_data(R&& res, D&& del)... : unique_resource_data(static_cast< R&& >(res), static_cast< D&& >(del), traits_type::is_allocated(static_cast< R&& >(res))) { }
The `static_cast
` look wrong. Should that be a std::move or std::forward? It is std::forward, but I had to check to be sure. (see above where a similar cast was a std::move) To me it looks like it`is_allocated` should not have a cast, should it? What if it is implemented to accept an instance, you castit to an rvalue, i.e. move it into that call and then use the moved-from value to construct `unique_resource_data` Similar for the deleter where using std::forward makes the intent clear. Thanks, I will take a look at that code. Quite possibly you're right, and I should avoid forwarding to is_allocated.
This should now be fixed on develop. Also, on the topic of using std::swap, I have changed the code to use boost::core::invoke_swap to swap bools, since I'm already using it to swap resources and deleters.
Alexander Grund wrote:
Am 30.11.23 um 18:49 schrieb Andrey Semashev via Boost:
I don't want to include <functional> just for std::reference_wrapper. I don't want to include <algorithm> just for std::swap. I don't want to include <utility> just for std::move. I don't want to include <functional> just for that trivial function object wrapper. I collected all such statements from your replies and would like to object: Reimplementing std-library components to avoid an include looks very wrong to me.
Not only is it likely premature optimization: User code including your headers likely included those files already making the include "free". Especially as many std-headers transitively include <utility> or even <algorithm>. And 2nd: With the collection above there are now 2 points obvious that <functional> is not included "just for x" and then "just for y". So now you have 2 reasons already to include it. And finally this is about readability: Everyone knows what `std::move(that)` does, but it is not that obvious for `static_cast< unique_resource_data&& >(that)` Similar for swapping "m_allocated" being expanded to 3 lines instead of `std::swap` obfuscating what it does. And ref_wrapper begs the question if and how it is different to std::reference_wrapper
TLDR: I'd strongly suggest to use the std-library where possible to a) not reinvent the wheel and b) improve readability by using existing idioms/names.
Unfortunately, including <functional> carries a very real cost nowadays, and this does lead to user complaints. <functional>, -std=c++03: 721 lines <functional>, -std=c++11: 12491 lines <functional>, -std=c++14: 13661 lines <functional>, -std=c++17: 33458 lines <functional>, -std=c++20: 37201 lines <functional>, -std=c++23: 37252 lines (GCC 11.3.0) The story of <algorithm> is similar: C++03: 9279 C++11: 14332 C++14: 14854 C++17: 34143 C++20: 56796 C++23: 56904 <utility> is cheaper: C++03: 218 C++11: 3271 C++14: 3504 C++17: 4054 C++20: 6411 C++23: 6462 Few know this, specifically how much things changed with C++17/C++20. Incidentally, std::swap is in <utility> starting from C++11. Having to include 37K lines just to get std::less or std::hash is a crime against humanity, but at least modules will fix everything no more than 15 years from now. Maybe even less!
Reminder that the review period for the proposed Boost.Scope ends on
the 5th of December. If you are planning to review the library, you
should probably get to it now.
пт, 24 нояб. 2023 г. в 23:58, Дмитрий Архипов
Dear Boost community. The peer review of the proposed Boost.Scope will start on 26th of November and continue until December 5th. Boost.Scope is a small library implementing utilities defined in
from C++ Extensions for Library Fundamentals v3 with a few extensions. Namely, the library contains: * A number of scope guards for various use cases. * A unique resource wrapper that automatically frees the resource on destruction. * Utilities for wrapping POSIX-like file descriptors in the unique resource wrapper. You can find the source code of the library at https://github.com/Lastique/scope and read the documentation at https://lastique.github.io/scope/libs/scope/doc/html/index.html. The library is header-only and thus it is fairly easy to try it out. In addition, the library can be used with Conan and vcpkg (see its README for instructions on how to do that). Finally, there's a single header version suitable for Compiler Explorer (https://raw.githubusercontent.com/Lastique/scope/single-header/include/boost...).
As the library is not domain-specific, everyone is very welcome to contribute a review either by sending it to the Boost mailing list, or me personally. In your review please state whether you recommend to reject or accept the library into Boost, and whether you suggest any conditions for acceptance.
Thanks in advance for your time and effort!
Dmitry Arkhipov, Staff Engineer at The C++ Alliance.
The review submission period for the proposed Boost.Scope has ended. I
want to thank everyone who has submitted a review and participated in
discussions. And of course, I want to thank the library author, Andrey
Semashev. I will soon return with a decision.
вс, 3 дек. 2023 г. в 19:28, Дмитрий Архипов
Reminder that the review period for the proposed Boost.Scope ends on the 5th of December. If you are planning to review the library, you should probably get to it now.
пт, 24 нояб. 2023 г. в 23:58, Дмитрий Архипов
: Dear Boost community. The peer review of the proposed Boost.Scope will start on 26th of November and continue until December 5th. Boost.Scope is a small library implementing utilities defined in
from C++ Extensions for Library Fundamentals v3 with a few extensions. Namely, the library contains: * A number of scope guards for various use cases. * A unique resource wrapper that automatically frees the resource on destruction. * Utilities for wrapping POSIX-like file descriptors in the unique resource wrapper. You can find the source code of the library at https://github.com/Lastique/scope and read the documentation at https://lastique.github.io/scope/libs/scope/doc/html/index.html. The library is header-only and thus it is fairly easy to try it out. In addition, the library can be used with Conan and vcpkg (see its README for instructions on how to do that). Finally, there's a single header version suitable for Compiler Explorer (https://raw.githubusercontent.com/Lastique/scope/single-header/include/boost...).
As the library is not domain-specific, everyone is very welcome to contribute a review either by sending it to the Boost mailing list, or me personally. In your review please state whether you recommend to reject or accept the library into Boost, and whether you suggest any conditions for acceptance.
Thanks in advance for your time and effort!
Dmitry Arkhipov, Staff Engineer at The C++ Alliance.
participants (16)
-
Alexander Grund
-
Andrea Bocci
-
Andrey Semashev
-
Andrzej Krzemienski
-
Dominique Devienne
-
Jeff Garland
-
Julien Blanc
-
Klemens Morgenstern
-
Niall Douglas
-
Peter Dimov
-
Rainer Deyke
-
René Ferdinand Rivera Morell
-
Richard Hodges
-
Robert Ramey
-
Vinnie Falco
-
Дмитрий Архипов