Search code examples
c++boost-asio

Purpose of return value in non-exception overloads


Boost ASIO usually has a duplicated API when one function may throw an exception and another one does not. For example:

void close();
boost::system::error_code close(
    boost::system::error_code & ec);

or

void shutdown(
    shutdown_type what);
boost::system::error_code shutdown(
    shutdown_type what,
    boost::system::error_code & ec);

My question is: why does the second version of the function (which doesn't throw an exception) use a return value (boost::system::error_code) although it already takes a variable to indicate an error via input parameter (boost::system::error_code & ec)?

As I can see from the Boost ASIO examples the return value usually is ignored.

Update 0: @Persixty pointed out that Boost ASIO has differences in API across different versions:

In other words, the modern version of the library should return void.

I write should because on my host (Ubuntu 24.04) I use Boost ASIO v1.83, but it still returns an error code:

/usr/include/boost/asio/detail/reactive_socket_service.hpp

  // Disable sends or receives on the socket.
  boost::system::error_code shutdown(base_implementation_type& impl,
      socket_base::shutdown_type what, boost::system::error_code& ec)
  {
    socket_ops::shutdown(impl.socket_, what, ec);

    BOOST_ASIO_ERROR_LOCATION(ec);
    return ec;
  }

Or:

/usr/include/boost/asio/detail/win_iocp_socket_service.hpp

  // Disable sends or receives on the socket.
  boost::system::error_code shutdown(base_implementation_type& impl,
      socket_base::shutdown_type what, boost::system::error_code& ec)
  {
    socket_ops::shutdown(impl.socket_, what, ec);
    return ec;
  }

Solution

  • There's none. It is inherently inconsistent because it cannot be used for non-void operations.

    Asio's developer has realized this and deprecated the return value. If you compile with BOOST_ASIO_NO_DEPRECATED then the functions will return void:

      BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
      {
        impl_.get_service().close(impl_.get_implementation(), ec);
        BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
      }
    

    Where config.hpp contains:

    // Helper macros to manage transition away from error_code return values.
    #if defined(BOOST_ASIO_NO_DEPRECATED)
    # define BOOST_ASIO_SYNC_OP_VOID void
    # define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return
    #else // defined(BOOST_ASIO_NO_DEPRECATED)
    # define BOOST_ASIO_SYNC_OP_VOID boost::system::error_code
    # define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return e
    #endif // defined(BOOST_ASIO_NO_DEPRECATED)
    

    The deprecation stems from 2017 with the initial merge of NetworkingTS compatibility changes: https://github.com/boostorg/asio/commit/b60e92b13ef68dfbb9af180d76eae41d22e19356