Boost logo

Boost :

Subject: Re: [boost] [system] Would it be possible to trial a breaking change to Boost.System and see what happens?
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2018-01-12 19:29:26


On 01/12/18 22:03, Peter Dimov via Boost wrote:
> Andrey Semashev wrote:
>>    void foo(error_code& err)
>>    {
>>      // Do stuff...
>>      err = make_error_code(success); // error_code(0, my_category)
>>    }
> ...
>> I suppose, you could argue that I could avoid `err` initialization in
>> `foo`, but that is a matter of taste and whether you want to rely on
>> the initial state of `err` on entry into `foo`.
>
> No, I'm not going to argue that; it's idiomatic to clear `err` on entry:
>
> void foo( error_code& err )
> {
>    err.clear();
>    // do stuff
> }
>
> with the alternative
>
>    err.assign( 0, err.category() );
>
> being used nowadays to avoid the overhead in .clear caused by the "magic
> static" Niall talks about.
>
> This latter "idiom" is obviously broken after NIall's suggested change
> though.

I don't think this matches my intent. The `foo` function belongs to the
domain that defines error codes described by the `my_errors` enum and it
is supposed to return one of those codes. Preserving whatever error
category was set in `err` on entry does not achieve that. What I want is
that `err` has `my_category` unconditionally on return from `foo`.

>> I'm also not happy to have to convert that initialization to
>>
>>      err = error_code();
>>
>> because it loses information about the error category, which may be
>> useful if I want to print `err` to log even if it is a success.
>
> Interesting. You rely on there being different success error_codes?

Yes, mostly for diagnostic purposes. Although it may also be a useful
feature to check the domain when comparing two error codes.

> How would you suggest we solve the problem of zero being an error in
> some contexts?

Besides moving the check for the error code into the category? I
suppose, `make_error_code` could perform some kind of mapping onto
another enum that has success value of 0. It can be as simple as this:

   enum foreign_errors
   {
     error = 0,
     success = 1
   };

   enum class internal_errors
   {
     error = -1,
     success = 0
   };

   error_code make_error_code(foreign_errors ec)
   {
     return error_code(ec - 1, my_category);
   }

   error_code make_error_code(internal_errors ec)
   {
     return error_code(ec, my_category);
   }

Another solution would be to make error category have a public member,
which is cheap to access, that would return the "success" value.

   // std::error_category
   class error_category
   {
     int success_value;

   public:
     explicit error_category(int sv = 0) : success_value(sv) {}
     int get_success_value() const noexcept { return success_value; }
   };

   class my_category final :
     public error_category
   {
   public:
     my_category() : error_category(1) {}
   };

   bool error_code::operator bool() const
   {
     return value() != category().get_success_value();
   }


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk