Proposed SG14 <system_error2> ready for feedback
Back after the Outcome discussion died down, I started a thread
discussing making breaking changes to Boost.System to test the
feasibility of fixing some of the unfortunate design choices now
apparent through hindsight in `
2018-02-28 23:10 GMT+01:00 Niall Douglas via Boost
Back after the Outcome discussion died down, I started a thread discussing making breaking changes to Boost.System to test the feasibility of fixing some of the unfortunate design choices now apparent through hindsight in `
`. I won one argument - constexprification - the others I lost. I said at the time that I'd go off and make a better mousetrap i.e. a proposed ` `. That proposed `
` is now ready for feedback: Single file include: https://github.com/ned14/status-code/raw/develop/ single-header/system_error2.hpp
The github readme at https://github.com/ned14/status-code gives a clear description how I can make use of POSIX and Windows-standard error codes. Could we have similar short and clear examples illustrating how one can: 1. Create a custom error_category (or equivalent thing) 2. Use parametrized statuc_code 3. Use type-erased status_code Regards, &rzej;
The github readme at https://github.com/ned14/status-code gives a clear description how I can make use of POSIX and Windows-standard error codes.
It must therefore not be self obvious? Darn. I had thought it very
simple, basically
Could we have similar short and clear examples illustrating how one can: 1. Create a custom error_category (or equivalent thing) 2. Use parametrized statuc_code
There is a test custom domain at https://github.com/ned14/status-code/blob/master/test/main.cpp#L44. But how about a mini-tutorial on building a custom code domain whose status code wraps any arbitrary thrown C++ exception? It looks like SG14 and WG21 is going to need one of those in any case.
3. Use type-erased status_code
Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
2018-03-01 18:57 GMT+01:00 Niall Douglas via Boost
The github readme at https://github.com/ned14/status-code gives a clear description how I can make use of POSIX and Windows-standard error codes.
It must therefore not be self obvious? Darn. I had thought it very simple, basically
with a few obvious tweaks. Not worth much explaining, anyway.
Not obvious to me: especially the templetized codes, and two kinds of type
erasure. This part of the design is definitely more complicated than the
original
Could we have similar short and clear examples illustrating how one can: 1. Create a custom error_category (or equivalent thing) 2. Use parametrized statuc_code
There is a test custom domain at https://github.com/ned14/status-code/blob/master/test/main.cpp#L44.
But how about a mini-tutorial on building a custom code domain whose status code wraps any arbitrary thrown C++ exception? It looks like SG14 and WG21 is going to need one of those in any case.
Any information would be useful, but I think it is more basic things that
are insufficiently described.
For now, consider it a feedback on what a casual reader will not understand
about
Not obvious to me: especially the templetized codes, and two kinds of type erasure. This part of the design is definitely more complicated than the original
. I would expect examples and some rationale.
Oh ok. Thanks for explaining.
If you choose to describe
as a diff from , I would expect all relevant differences to be mentioned in the docs. For instance I can see you use `status_code_domain` rather than `error_category`. This looks like an improvement in clarity.
Previous feedback from Arthur suggested that.
Also, how do you handle error code names without strings? Do i need to define my own string_ref?
The default string_ref implementation returns unmanaged static const char strings. So if your strings are those, you need do nothing. The posix_code domain implementation shows how to implement a reference counted string retrieved dynamically from the system.
Similarly, how did you fix the "duplicated globals" problem on Windows?
That's actually a problem on POSIX as well. All platforms are affected. You cannot make header only libraries with custom error category which work right on any platform. It was fixed by making the category source a constexpr variable, and each is given a 64 bit random unique id by its author from random.org. If the ids match, the domains are considered equal. Much of the time the compiler can therefore skip id comparison, as it knows both sources are constexpr and it knows the unique id at constexpr. But if push comes to shove, it can compare the ids, and it doesn't matter if the singleton is not unique in the process.
Also, there is this paragraph:
The relationship between std::error_code and std::error_condition is confusing to many users reading code based on
, specifically when is a comparison between codes *semantic* or *literal*? status_code makes all comparisons *semantic*, *always*. If you want a literal comparison, you can do one by hand by comparing domains and values directly. I fail to see what you mean by "semantic comparison" and "literal comparison". Do they mean comparing error_code to error_category and comparing error_code to error_code respectively?
Correct. So, in error_category's case, semantic comparisons occur via .equivalent() which is called when operator==() is done between an error_code and error_condition. It's the same for status code domain, there is an .equivalent() function. The difference is that there is no such thing as error conditions, and operator==() always calls .equivalent(). We also don't provide ordering nor hashing for status code, as equality testing is semantic. These ought to not be used in maps without a custom comparison.
Any information would be useful, but I think it is more basic things that are insufficiently described. For now, consider it a feedback on what a casual reader will not understand about
.
I'm hesitant to write much in the way of docs until the design has been empirically tested in AFIO. But it's basically a concrete implementation of the possible improvements to error_code we discussed here a few weeks back. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
Niall Douglas wrote:
It was fixed by making the category source a constexpr variable, and each is given a 64 bit random unique id by its author from random.org. If the ids match, the domains are considered equal.
That's something I was considering for Boost.System (literally the same thing, a random 64 bit ID). Unfortunately, the virtual destructor makes error_category a non-literal type, so categories can't be constexpr variables. Hence, my earlier inquiry about the switch to a protected nonvirtual ~error_category. There is talk of/hope for language changes allowing constexpr virtuals, but it's yet unclear whether we'll get that or if so, when.
It was fixed by making the category source a constexpr variable, and each is given a 64 bit random unique id by its author from random.org. If the ids match, the domains are considered equal.
That's something I was considering for Boost.System (literally the same thing, a random 64 bit ID). Unfortunately, the virtual destructor makes error_category a non-literal type, so categories can't be constexpr variables. Hence, my earlier inquiry about the switch to a protected nonvirtual ~error_category.
status code domain has a trivial destructor, and thus is 100% constexpr
end to end of its lifetime.
You should be aware Peter that your input during the previous
discussions was unusually valuable in deciding the design of
On Fri, Mar 2, 2018 at 2:26 PM, Niall Douglas via Boost
ASIO's supremacy has changed what the C++ user base expect when they see an error_code& API. They expect that all failures will be indicated by said error_code&.
Asio functions which have `error_code&` in their signature can still throw exceptions. Not sure why you think otherwise. Regards
ASIO's supremacy has changed what the C++ user base expect when they see an error_code& API. They expect that all failures will be indicated by said error_code&.
Asio functions which have `error_code&` in their signature can still throw exceptions. Not sure why you think otherwise.
ASIO itself never does I believe. That's what I was referring to. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
But how about a mini-tutorial on building a custom code domain whose status code wraps any arbitrary thrown C++ exception? It looks like SG14 and WG21 is going to need one of those in any case.
That worked example is written and can be viewed at
https://github.com/ned14/status-code/blob/master/doc/custom_domain_worked_ex....
It should explain a lot more of how
On 1/03/2018 11:10, Niall Douglas wrote:
On all systems, there is a typedef `system_code` which is to the erased status code sufficiently large that you are guaranteed that all possible system error coding schemes can be safely erased into it. For POSIX, this is `status_code
`, as `int` can hold all possible error codings. For Windows, this is `status_code >`, as `intptr_t` can hold any of a `DWORD`, a `LONG` and a `HRESULT`.
DWORD (aka uint32_t) can hold any of DWORD, LONG, and HRESULT. Or use LONG (aka int32_t) if you want to retain signedness of LONGs, though I don't think any Win32 APIs require this. In any case intptr_t is either larger than needed to preserve the value bits (in 64-bit applications) or smaller than needed to preserve the value and sign (in 32-bit applications), so this seems like an inappropriate choice. (HRESULT is not a pointer type, despite most other H* types being derived from HANDLE. Yay for consistency.)
On all systems, there is a typedef `system_code` which is to the erased status code sufficiently large that you are guaranteed that all possible system error coding schemes can be safely erased into it. For POSIX, this is `status_code
`, as `int` can hold all possible error codings. For Windows, this is `status_code >`, as `intptr_t` can hold any of a `DWORD`, a `LONG` and a `HRESULT`. DWORD (aka uint32_t) can hold any of DWORD, LONG, and HRESULT.
Or use LONG (aka int32_t) if you want to retain signedness of LONGs, though I don't think any Win32 APIs require this.
In any case intptr_t is either larger than needed to preserve the value bits (in 64-bit applications) or smaller than needed to preserve the value and sign (in 32-bit applications), so this seems like an inappropriate choice.
Structure alignment would align any int to the pointer, so same space in any case. Two CPU registers.
(HRESULT is not a pointer type, despite most other H* types being derived from HANDLE. Yay for consistency.)
I did actually look that up before choosing it, and at the time found one of the platform configs was defining it to HANDLE. But I can't find that again now, so I must have been tired and confused. In private discussions with some on WG21, it is felt that status code needs to always be two CPU registers exactly. So I'll be bumping that to intptr_t on all platforms. It's also been requested that a new `error` type be created which refines status_code. `error` always represents a failed status_code, and nothing else. It cannot be empty, it cannot be success. Outcome will be using this new type `error` as its E type in its experimental form. You may be seeing a ton load more about this proposed `error` type during the coming year. It is very exciting. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
On 5/03/2018 22:13, Niall Douglas wrote:
In any case intptr_t is either larger than needed to preserve the value bits (in 64-bit applications) or smaller than needed to preserve the value and sign (in 32-bit applications), so this seems like an inappropriate choice.
Structure alignment would align any int to the pointer, so same space in any case. Two CPU registers.
Perhaps, but the difference between value bits and padding bits is significant, and it seems pointless (and prone to compiler warnings about losing significant bits if you then try to assign the value back to its "real" type) to misrepresent its size.
In private discussions with some on WG21, it is felt that status code needs to always be two CPU registers exactly. So I'll be bumping that to intptr_t on all platforms.
Why? What benefit does this provide?
Structure alignment would align any int to the pointer, so same space in any case. Two CPU registers.
Perhaps, but the difference between value bits and padding bits is significant, and it seems pointless (and prone to compiler warnings about losing significant bits if you then try to assign the value back to its "real" type) to misrepresent its size.
Ah, I have a cunning piece of code to handle that. The problem was if the original source was say a char padded by the compiler to an intptr_t, and you erase that into an intptr_t. Seven bytes are therefore being accessed as UB, and random data could appear in there. Both of which are unhelpful. So I have a bit of trampoline code which constexpr initialises a union of the source type and the intptr_t which is initialised to all bits zero. We then set the source type, and read back the intptr_t. This ensures that the padding bits are all bits zero in the type erased form.
In private discussions with some on WG21, it is felt that status code needs to always be two CPU registers exactly. So I'll be bumping that to intptr_t on all platforms.
Why? What benefit does this provide?
So the compiler could be given a hard guarantee that an `error` can always be trivially returned. On x64 Itanium ABI, RAX+RDX is used to return a 16 byte value. The MSVC ABI currently does not use that mechanism on x64, it can only return up to 8 bytes trivially. A function potentially returning `error` would be mangled to say that it does so. The compiler therefore knows that one of the CPU flags (e.g. DF or SF) means whether to interpret RAX+RDX as an `error` or as an ordinary non-failure return value. That's why it's important that `error` fit into two CPU registers. `error` is now ready incidentally. https://ned14.github.io/status-code/doc_error.html. It's looking very promising. Be aware that https://wg21.link/P0709 currently results in a 404. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
participants (5)
-
Andrzej Krzemienski
-
Gavin Lambert
-
Niall Douglas
-
Peter Dimov
-
Vinnie Falco