Date: Thu, 31 Jul 2025 13:38:25 -0500
Hi,
A tool to return not just from the current function from the caller is
dangerous, extremely niche, hard to reason about, and difficult to
implement. There would also have to be many limitations on where you could
use a function that does a caller return. A better way to do this is P2561.
Either way, some language evolution has to happen for improving error
propagation but C++ should just add first order language support for this.
Adding some new tool that would only be useful for implementing an error
propagation helper is pretty circuitous.
Cheers,
Jeremy
On Thu, Jul 31, 2025 at 9:35 AM Ayrton Lachat via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> Hello,
>
> This proposal is about adding a way for a callee to return from the
> caller. Such a feature can be useful to avoid the multiplication of
> `if`(-`else`) blocks related to error handling, and more specifically the
> one that just forwards the error. For example, the following code :
>
> ```cpp
> std::expected<std::string, int> someFailableOperation() noexcept;
>
> std::expected<void, int> foo() noexcept {
> auto result {someFailableOperation()};
> if (!result)
> return result.error();
> std::println("The result: {}", *result);
> return {};
> }
> ```
>
> would become the much nicer :
>
> ```cpp
> std::expected<void, int> foo() noexcept {
> std::println("The result: {}", unwrap(result));
> return {};
> }
> ```
>
> This `unwrap` function could even in the future be replaced by some
> operator (question mark ? certainly, but not sure if this should be in the
> same proposal).
>
> First, we need to define some goals of this feature to make it play nice
> with existing code and for it to not create disturbing workflow :
>
> 1. A function capable of *caller-return *must be tag as such in the
> prototype (even make it part of the type, like for noexcept?). In this
> way, not every random function can start doing it, and the
> abi-compatibility is preserved (as such a change would certainly require
> abi change).
> 2. Having a way to get the *caller-return-type *in the callee, so we
> can make conditional error handling (mostly conversion).
> 3. Having a way to force your function to be used only when the
> *caller-return-type* match certain requirements.
>
>
> With those requirements, I propose the following syntax :
>
> ```cpp
> (1) caller_return < _type-parameter_ > _function-declaration_
> (2) caller_return < _type-parameter_ > requires _constraint_
> _function-declaration_
> ```
>
> Where:
>
> - *type-parameter *: a single type parameter, may be constrained
> - *function-declaration *: a usual function declaration, may be
> templated
> - *constraint *: some constraint on the *type-parameter*. The
> requires-clause is merged with the one from usual template, if the function
> is templated.
>
>
> A function mark _caller-return_ is implicitly _inline_.
>
> And we add the following usage for the `caller_return` keyword, inside a
> function scope :
>
> ```cpp
> (1) caller_return;
> (2) caller_return _expr_;
> ```
>
> When this instruction is encountered, the caller is returned from, with
> the value of *expr* (or void for (1)). The type of the
> caller-return-value must meet the same requirements as if it was used in a
> normal return statement in the caller.
>
> Of course, this usage of the keyword is limited to function marked
> caller-return.
>
> With this syntax, the `unwrap` function of the example at the top can be
> written as follow :
>
> ```cpp
> caller_return</* is-expected-concept */ CallerReturn>
> template <typename Res, std::convertible_to<typename
> CallerReturn::error_type> Err>
> constexpr Res unwrap(std::expected<Res, Err> exp) noexcept {
> if (exp)
> return *exp;
> caller_return std::unexpected(static_cast<typename
> CallerReturn::error_type> (exp.error()));
> }
> ```
>
> There is still the question of which functions are allowed to be
> caller-return. Destructor should definitely not be caller-return. What
> about constructor? I don't have an opinion on whether they should be
> allowed or not. Operator overloading? One of the main appeals of this
> feature is the possibility to allow implementation of a question mark
> operator, so operator overloading should be allowed. But using it with the
> current operator can make the flow of a function not obvious at all
> (because who read the prototype of operators). And people will certainly
> use it on the dereference operator, which is not a behavior most C++
> developer expect. So, I think it should be disallowed on operator
> overloading, except for a question mark operator (if one is added).
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
A tool to return not just from the current function from the caller is
dangerous, extremely niche, hard to reason about, and difficult to
implement. There would also have to be many limitations on where you could
use a function that does a caller return. A better way to do this is P2561.
Either way, some language evolution has to happen for improving error
propagation but C++ should just add first order language support for this.
Adding some new tool that would only be useful for implementing an error
propagation helper is pretty circuitous.
Cheers,
Jeremy
On Thu, Jul 31, 2025 at 9:35 AM Ayrton Lachat via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> Hello,
>
> This proposal is about adding a way for a callee to return from the
> caller. Such a feature can be useful to avoid the multiplication of
> `if`(-`else`) blocks related to error handling, and more specifically the
> one that just forwards the error. For example, the following code :
>
> ```cpp
> std::expected<std::string, int> someFailableOperation() noexcept;
>
> std::expected<void, int> foo() noexcept {
> auto result {someFailableOperation()};
> if (!result)
> return result.error();
> std::println("The result: {}", *result);
> return {};
> }
> ```
>
> would become the much nicer :
>
> ```cpp
> std::expected<void, int> foo() noexcept {
> std::println("The result: {}", unwrap(result));
> return {};
> }
> ```
>
> This `unwrap` function could even in the future be replaced by some
> operator (question mark ? certainly, but not sure if this should be in the
> same proposal).
>
> First, we need to define some goals of this feature to make it play nice
> with existing code and for it to not create disturbing workflow :
>
> 1. A function capable of *caller-return *must be tag as such in the
> prototype (even make it part of the type, like for noexcept?). In this
> way, not every random function can start doing it, and the
> abi-compatibility is preserved (as such a change would certainly require
> abi change).
> 2. Having a way to get the *caller-return-type *in the callee, so we
> can make conditional error handling (mostly conversion).
> 3. Having a way to force your function to be used only when the
> *caller-return-type* match certain requirements.
>
>
> With those requirements, I propose the following syntax :
>
> ```cpp
> (1) caller_return < _type-parameter_ > _function-declaration_
> (2) caller_return < _type-parameter_ > requires _constraint_
> _function-declaration_
> ```
>
> Where:
>
> - *type-parameter *: a single type parameter, may be constrained
> - *function-declaration *: a usual function declaration, may be
> templated
> - *constraint *: some constraint on the *type-parameter*. The
> requires-clause is merged with the one from usual template, if the function
> is templated.
>
>
> A function mark _caller-return_ is implicitly _inline_.
>
> And we add the following usage for the `caller_return` keyword, inside a
> function scope :
>
> ```cpp
> (1) caller_return;
> (2) caller_return _expr_;
> ```
>
> When this instruction is encountered, the caller is returned from, with
> the value of *expr* (or void for (1)). The type of the
> caller-return-value must meet the same requirements as if it was used in a
> normal return statement in the caller.
>
> Of course, this usage of the keyword is limited to function marked
> caller-return.
>
> With this syntax, the `unwrap` function of the example at the top can be
> written as follow :
>
> ```cpp
> caller_return</* is-expected-concept */ CallerReturn>
> template <typename Res, std::convertible_to<typename
> CallerReturn::error_type> Err>
> constexpr Res unwrap(std::expected<Res, Err> exp) noexcept {
> if (exp)
> return *exp;
> caller_return std::unexpected(static_cast<typename
> CallerReturn::error_type> (exp.error()));
> }
> ```
>
> There is still the question of which functions are allowed to be
> caller-return. Destructor should definitely not be caller-return. What
> about constructor? I don't have an opinion on whether they should be
> allowed or not. Operator overloading? One of the main appeals of this
> feature is the possibility to allow implementation of a question mark
> operator, so operator overloading should be allowed. But using it with the
> current operator can make the flow of a function not obvious at all
> (because who read the prototype of operators). And people will certainly
> use it on the dereference operator, which is not a behavior most C++
> developer expect. So, I think it should be disallowed on operator
> overloading, except for a question mark operator (if one is added).
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2025-07-31 18:38:43