When to use `error` and when to use `status_code` from SYSTEM_ERROR2_NAMESPACE
qknight opened this issue · comments
Hey,
with this example below, copied from the Readme.md we assign:
SYSTEM_ERROR2_CONSTEXPR14 auto v = another_namespace::status_code(another_namespace::AnotherCode::success1);
SYSTEM_ERROR2_NAMESPACE::error err = v;
This terminates the program according to the check in the source in status_code.hpp!
We wonder why should I use SYSTEM_ERROR2_NAMESPACE::error vs. SYSTEM_ERROR2_NAMESPACE::status_code at all? When does it make sense to use ::error
and when to use ::status_code
Readme.md (the source code with small adaptions)
// qknight: added example code from status-code readme.md to play with
// https://github.com/ned14/status-code#quick-synthesis-of-a-custom-status-code-domain-for-any-arbitrary-enumeration-type
#ifdef _WIN32
#include "com_code.hpp"
#else
#include "getaddrinfo_code.hpp"
#endif
#include "iostream_support.hpp"
#include "std_error_code.hpp"
#include "system_error2.hpp"
#include <cstdio>
#include <cstring> // for strdup, strlen
#include <iostream>
#include <memory>
#include <string>
#include <assert.h>
// This is some third party enumeration type in another namespace
namespace another_namespace
{
// "Initialiser list" custom status code domain
enum class AnotherCode : size_t
{
success1,
goaway,
success2,
error2
};
} // namespace another_namespace
// To synthesise a custom status code domain for `AnotherCode`, inject the following
// template specialisation:
SYSTEM_ERROR2_NAMESPACE_BEGIN
template <>
struct quick_status_code_from_enum<another_namespace::AnotherCode>
: quick_status_code_from_enum_defaults<another_namespace::AnotherCode>
{
// Text name of the enum
static constexpr const auto domain_name = "Another Code";
// Unique UUID for the enum. PLEASE use https://www.random.org/cgi-bin/randbyte?nbytes=16&format=h
static constexpr const auto domain_uuid = "{be201f65-3962-dd0e-1266-a72e63776a42}";
// Map of each enum value to its text string, and list of semantically equivalent errc's
static const std::initializer_list<mapping> &value_mappings()
{
static const std::initializer_list<mapping> v = {
// Format is: { enum value, "string representation", { list of errc mappings ... } }
{another_namespace::AnotherCode::success1, "Success 1", {errc::success}}, //
{another_namespace::AnotherCode::goaway, "Go away", {errc::permission_denied}}, //
{another_namespace::AnotherCode::success2, "Success 2", {errc::success}}, //
{another_namespace::AnotherCode::error2, "Error 2", {}}, //
};
return v;
}
// Completely optional definition of mixin for the status code synthesised from `Enum`.
// It can be omitted.
template <class Base> struct mixin : Base
{
using Base::Base;
// A custom method on the synthesised status code
constexpr int custom_method() const { return 42; }
};
};
SYSTEM_ERROR2_NAMESPACE_END
// If you wish easy manufacture of status codes from AnotherCode:
namespace another_namespace
{
// ADL discovered, must be in same namespace as AnotherCode
constexpr inline
SYSTEM_ERROR2_NAMESPACE::quick_status_code_from_enum_code<AnotherCode>
status_code(AnotherCode c) { return c; }
} // namespace another_namespace
void example4() {
// Make a status code of the synthesised code domain for `AnotherCode`
SYSTEM_ERROR2_CONSTEXPR14 auto v = another_namespace::status_code(another_namespace::AnotherCode::success1);
// If you don't need custom methods, just use system_code, all erased
// status codes recognise quick_status_code_from_enum
SYSTEM_ERROR2_NAMESPACE::system_code v2(another_namespace::AnotherCode::error2);
// this ends the program, but why should i use SYSTEM_ERROR2_NAMESPACE::error vs. SYSTEM_ERROR2_NAMESPACE::system_code at all?
SYSTEM_ERROR2_NAMESPACE::error err = v;
std::cout << "executing two asserts... in example 4" << std::endl;
assert(v.value() == another_namespace::AnotherCode::success1);
assert(v.custom_method() == 42);
};
Additional wish
Could you add this code to the examples/ folder also?
with this example below, copied from the Readme.md we assign:
SYSTEM_ERROR2_CONSTEXPR14 auto v = another_namespace::status_code(another_namespace::AnotherCode::success1); SYSTEM_ERROR2_NAMESPACE::error err = v;
This terminates the program according to the check in the source in status_code.hpp!
We wonder why should I use SYSTEM_ERROR2_NAMESPACE::error vs. SYSTEM_ERROR2_NAMESPACE::status_code at all? When does it make sense to use
::error
and when to use::status_code
The relationship here is as follows:
system_code
is astatus_code
erased into anintptr_t
.error
is anerrored_status_code
erased into anintptr_t
.errored_status_code
is astatus_code
for whom it is guaranteed that.success()
is false, which was originally going to be guaranteed using C++ contracts before those got axed. The next closest equivalent to Contracts is terminating the process.
So the idea is that an operation can return a status code which may be successful (e.g. with warning or additional info), or may be a failure with cause. If you wish to promise in the C++ type system that a status code will always be a failure, you use errored_*
or error
. The compiler may be able to make extra optimisations in this situation (no current compiler can).
Hopefully that makes sense.
Re: adding the quick status code from enum example, no problem I'll do that there now.