Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moving toward stateless I/O without exceptions #77

Open
fpagliughi opened this issue Mar 19, 2023 · 2 comments
Open

Moving toward stateless I/O without exceptions #77

fpagliughi opened this issue Mar 19, 2023 · 2 comments
Milestone

Comments

@fpagliughi
Copy link
Owner

Commit 784dc09 in PR #17 introduced stateless I/O functions, like read_r() and writre_r(), which return an ioresult type that wrap the success and specific error values derived from errno or GetLastError().

On an unrelated note, in Issue #72, @JakeSays suggested getting rid of exceptions in the few places they're used, and @ldgeng, suggested using std::error_code.

I was not even aware std::error_code existed, but it looks very appropriate for this library. It would be a good way to eliminate platform-specific differences of checking errors on Win32 that has been plaguing us already. And it would present a road forward for handling errors when TLS libraries are introduced in a future version of sockpp.

So, taken all together, I'm thinking of doing this...

  1. Convert the "last error" in the library to return an error code, like:
    std::error_code socket::get_last_error();
  1. Make a generic result<T> type where T is the success variant and error_code is the error.
    template <typename T>
    class result {
        /** The return value of an operation, if successful */
        T val_;
        /** The error returned from an operation, if failed */
        error_code err_;
    // ...
    };
  1. An ioresult would be a specialization of result<int>:
    using ioresul = result<int>;
  1. Remove exceptions and return a result<T> in their place. The whole API will be noexcept.
  2. Constructors that would have thrown now just set the last error, and thus would need to be checked (similar to iostreams, I guess).
  3. Phase out the need for maintaining the error state. In the next major release, move to all I/O operations being stateless, returning an ioresult. The only explicit need for the state would be checking the object after construction.

The last point would allow a single socket to be thread-safe for two threads where one reads from the socket and the other writes to it. This is a common pattern in socket apps in C, but couldn't be done in sockpp since get_last_error() is not thread safe.

@fpagliughi fpagliughi added this to the v0.9 milestone Mar 19, 2023
@fpagliughi

This comment was marked as outdated.

fpagliughi added a commit that referenced this issue Apr 29, 2023
…ore uniform with 'is_set()' and operator bool()'
@fpagliughi fpagliughi modified the milestones: v0.9, v0.10 Dec 11, 2023
@fpagliughi
Copy link
Owner Author

Here's how I think things will play out...

  1. The std::error_code and result<T> will be introduced in v0.9, but will only be used in a limited fashion, where useful.
  2. Some functions that had to throw previously to distinguish error types - like GAI errors instead of errno will now return a result<T> instead of throwing. These will be marked noexcept.
  3. In the few cases where exceptions are still useful, particularly in constructors, those will remain, but the classes will also provide comparable methods that take an error_code& parameter to return any failure state if encountered. So the application can choose to completely avoid exceptions if desired.
  4. A full conversion to stateless functions will likely happen in the following release, v0.10. This will eliminate the need for get_last_error() and make sockets somewhat more thread friendly by removing the cached error state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant