[system] The new Boost.System is now ready
The new Boost.System is now complete, on the develop branch: https://www.boost.org/doc/libs/develop/libs/system/ - header-only - even more constexpr than 1.68 - identifier-based category comparison - message() into a caller-supplied buffer - failed() The plan is to merge it to master at some point if no breakage is encountered on develop, so that it can go into the next release.
The new Boost.System is now complete, on the develop branch:
https://www.boost.org/doc/libs/develop/libs/system/
- header-only - even more constexpr than 1.68
https://pdimov.github.io/cpp-papers/P1195R0.html
- identifier-based category comparison
https://pdimov.github.io/cpp-papers/P1196R0.html
- message() into a caller-supplied buffer
https://pdimov.github.io/cpp-papers/P1197R0.html
- failed()
https://pdimov.github.io/cpp-papers/P1198R0.html
The plan is to merge it to master at some point if no breakage is encountered on develop, so that it can go into the next release.
On Fri, 5 Oct 2018 at 00:41, Peter Dimov via Boost
The new Boost.System is now complete, on the develop branch:
These are very welcome. Thank you for taking the time to do this. Looking forward to seeing this in the next boost release. R
https://www.boost.org/doc/libs/develop/libs/system/
- header-only - even more constexpr than 1.68
https://pdimov.github.io/cpp-papers/P1195R0.html
- identifier-based category comparison
https://pdimov.github.io/cpp-papers/P1196R0.html
- message() into a caller-supplied buffer
https://pdimov.github.io/cpp-papers/P1197R0.html
- failed()
https://pdimov.github.io/cpp-papers/P1198R0.html
The plan is to merge it to master at some point if no breakage is encountered on develop, so that it can go into the next release.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On 5/10/2018 11:37, Peter Dimov wrote:
The new Boost.System is now complete, on the develop branch:
https://www.boost.org/doc/libs/develop/libs/system/
- header-only - even more constexpr than 1.68
https://pdimov.github.io/cpp-papers/P1195R0.html
- identifier-based category comparison
https://pdimov.github.io/cpp-papers/P1196R0.html
- message() into a caller-supplied buffer
https://pdimov.github.io/cpp-papers/P1197R0.html
- failed()
https://pdimov.github.io/cpp-papers/P1198R0.html
The plan is to merge it to master at some point if no breakage is encountered on develop, so that it can go into the next release.
Looks good. I assume that the link to random.org implies that the proposed identifiers for generic_category and system_category were selected this way. I suggest calling this out a bit more explicitly as the preferred method of choosing identifiers for custom categories, as on the first reading I overlooked this and was wondering how they had been chosen. I also suspect that unless strongly encouraged to pick only random numbers, people are going to naturally try to pick "cute" identifiers (eg. ASCII encodings of words, a la FOURCC) or dumb identifiers (small integers), which have a much higher probability of collision. Also, in P1197R0, perhaps I'm missing some context (not having a copy of the standard handy) but it seems peculiar that the Effects of the two new message() overloads are ordered differently with respect to possibly returning a literal message pointer, ignoring buffer and len. Why is it that the second can do this but not the first?
Gavin Lambert wrote:
Also, in P1197R0, perhaps I'm missing some context (not having a copy of the standard handy) but it seems peculiar that the Effects of the two new message() overloads are ordered differently with respect to possibly returning a literal message pointer, ignoring buffer and len. Why is it that the second can do this but not the first?
The first specification ([syserr.errcat.virtuals]) describes the default implementation in error_category. This exists for backward compatibility. Since user-defined categories that only override the current `message` already exist, if the make the new overload pure, we'll break them. So we supply a default that calls the string overload and copies the string into the buffer. Since we have no idea what the returned string is, we can't return a literal under any circumstances. (Except on exception.) The second specification ([syserr.errcat.derived]) describes what classes derived from error_category need to do.
On 8/10/2018 12:37, Peter Dimov wrote:
The first specification ([syserr.errcat.virtuals]) describes the default implementation in error_category. This exists for backward compatibility. Since user-defined categories that only override the current `message` already exist, if the make the new overload pure, we'll break them. So we supply a default that calls the string overload and copies the string into the buffer.
While I can understand the desire to provide a useful message in that case, doesn't it defeat the purpose of providing a no-allocation overload? Granted that if it doesn't do this, then the caller would presumably get back an empty string ("oops, we couldn't get an error message without allocating") and then have to decide whether to call the allocating overload themselves or just live without the message. Which is perhaps more effort and less transparent, but I assume it probably would be the preferred choice for the people who wanted zero-allocation in the first place. There doesn't otherwise appear to be any way to "opt-out" of allocation. Another option might be to output a generic snprintf message along the lines of "error %s:%d" (category name and code, similar to operator<<(error_code) but avoiding that specific implementation). This might be slightly more user-useful, if there isn't a fallback to the allocating overload; with the caveat that it would make it harder for the caller to detect when they needed to decide whether to do that. So this choice is probably better left to the caller anyway.
Gavin Lambert wrote:
Another option might be to output a generic snprintf message along the lines of "error %s:%d" (category name and code, similar to operator<<(error_code) but avoiding that specific implementation). This might be slightly more user-useful, if there isn't a fallback to the allocating overload; with the caveat that it would make it harder for the caller to detect when they needed to decide whether to do that. So this choice is probably better left to the caller anyway.
This is a legitimate option. I admit I haven't given this much thought because the assumption was that having categories that do not override the new `message` would be just a temporary state of affairs. The desire to not allocate comes at least as much from people writing categories as from those using them; the objection was that even when your category _could_ return literals it had no way to do so. The default implementation comes into play in a scenario in which the client has "upgraded" to the new overload, but the (third party - system and generic are already up to date) category hasn't, and I've decided to preserve the message as much as possible rather than to enforce the "no allocation" property at the expense of losing the message. Maybe this is not the correct choice, I'm not sure. But again, this scenario should eventually never occur as third-party categories are updated. One argument in favor of "error %s:%d" is that it makes it obvious that the category needs to be updated, or stated differently, one argument in favor is that it would force people to update their categories. On the other hand, one argument against is that it would force people to update their categories, and people don't want to be forced to needlessly change working code. :-)
On 9/10/2018 03:22, Peter Dimov wrote:
I admit I haven't given this much thought because the assumption was that having categories that do not override the new `message` would be just a temporary state of affairs. The desire to not allocate comes at least as much from people writing categories as from those using them; the objection was that even when your category _could_ return literals it had no way to do so.
The default implementation comes into play in a scenario in which the client has "upgraded" to the new overload, but the (third party - system and generic are already up to date) category hasn't, and I've decided to preserve the message as much as possible rather than to enforce the "no allocation" property at the expense of losing the message. Maybe this is not the correct choice, I'm not sure. But again, this scenario should eventually never occur as third-party categories are updated.
I'm not sure either (so I hope that others chime in with their thoughts -- especially Niall, since he's worked with many of the people who I imagine would have strong opinions one way or the other). A related hesitation that I have is that while the caller can ask if there is a literal message (by passing nullptr,0) they can't otherwise ask for a possibly-dynamic-but-non-allocating (eg. snprintf) message. So if this fallback to the allocating-message() exists, it means that the caller either has to ask only for literal messages (thus failing to get snprintf messages) or they have to rely on out-of-band knowledge that the specific category of the error happens to support non-allocating messages, or risk hitting an undesirable allocating path. On the other hand, people who care about that sort of thing are perhaps more likely to use a custom STL or carefully chosen libraries known to not generate such errors, so perhaps this is not worth worrying about.
The default implementation comes into play in a scenario in which the client has "upgraded" to the new overload, but the (third party - system and generic are already up to date) category hasn't, and I've decided to preserve the message as much as possible rather than to enforce the "no allocation" property at the expense of losing the message. Maybe this is not the correct choice, I'm not sure. But again, this scenario should eventually never occur as third-party categories are updated.
I'm not sure either (so I hope that others chime in with their thoughts -- especially Niall, since he's worked with many of the people who I imagine would have strong opinions one way or the other).
I think Peter's choice is reasonable, given the constraints in play. But I also think the system_error design can only have its rough edges smoothed. It cannot be rescued. Peter disagrees. I've got a fair number of users using the SG14 v2 system_error design at https://github.com/ned14/status-code, some of which informed Peter's improvements of Boost.System. Once they wrap their heads around the weird template inversion, feedback has been universally positive. People just love the arbitrary payload facility, and the way it can be type erased and restored if all the constraints are met. They also like the zero allocation defaults, and not dragging in any heavy STL headers. You must explicitly opt in to allocation, unlike Boost.System. Still, WG21 have not yet judged SG14 v2 system_error. Until they do, we cannot know where it will go. Niall
On 10/05/18 00:37, Peter Dimov via Boost wrote:
- identifier-based category comparison
This states in Motivation that
"relying on address-based comparisons makes it impossible to declare
category objects constexpr and makes it impossible to declare
operator< constexpr"
Implementation adds the constexpr to operator<
"constexpr bool operator<(const error_category& rhs) const noexcept;"
with an as-if comment about the return value, which ends with an address
comparison:
"return less
- message() into a caller-supplied buffer
This document refers to strerror_r as a glibc thing. It is also Posix, which is probably a better reference: http://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror.html Other than that, I very much agree with your proposals.
Bjorn Reese wrote:
On 10/05/18 00:37, Peter Dimov via Boost wrote:
- identifier-based category comparison
This states in Motivation that
"relying on address-based comparisons makes it impossible to declare category objects constexpr and makes it impossible to declare operator< constexpr"
Implementation adds the constexpr to operator<
"constexpr bool operator<(const error_category& rhs) const noexcept;"
with an as-if comment about the return value, which ends with an address comparison:
"return less
()(this, &rhs);" How can this be made constexpr?
It's constexpr if you never reach this line. That is, if at least one of the categories you're comparing has an identifier, op< is constexpr.
- message() into a caller-supplied buffer
This document refers to strerror_r as a glibc thing. It is also Posix, which is probably a better reference:
http://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror.html
I'm referring specifically to the Glibc version, which returns `char const*` so that the implementation can return literals instead of using the buffer. The POSIX version returns an `int` and always copies into the buffer.
https://www.boost.org/doc/libs/develop/libs/system/
- header-only - even more constexpr than 1.68 - identifier-based category comparison - message() into a caller-supplied buffer - failed()
The plan is to merge it to master at some point if no breakage is encountered on develop, so that it can go into the next release.
Great bit of work there Peter. Outcome will benefit greatly from it. Thank you. Niall
participants (5)
-
Bjorn Reese
-
Gavin Lambert
-
Niall Douglas
-
Peter Dimov
-
Richard Hodges