I like this. It bears similarity to a slightly different use case that I brought up in https://lists.isocpp.org/std-proposals/2020/02/0964.php

It can already be done with callbacks, albeit with the control flow limitations that callbacks provide (e.g. It isn't possible to return from the parent scope). On that basis, simplifying the approach and allowing code blocks following a function call to act along similar lines as generic callbacks would be great for establishing multi-type pipelines without the overhead of std::variant and friends. Error handling is a part of that too.

On Mon, 8 Jun 2020, 12:51 Toby Brull via Std-Proposals, <std-proposals@lists.isocpp.org> wrote:
Yes, sorry, that should've had curly braces around it. Obviously, none of the above compiles, so I could not verify it through a compiler.

On the other hand, the same way alternative return-paths map to std::variant, I briefly thought about a similar mechanism that would map to std::tuple. This would basically mean that any function (and any return-path) could return multiple values (akin to a return value of type std::variant<std::tuple, std::tuple, ...>). So, you could rewrite the above function as

int, int parse_int_square(std::string_view const str)
  ->[parse_error] std::string
{
  auto const i = parse_int(str);
  return i, i * i;
}

int main() {
  // ...
  auto i, i_sq = parse_int_squared(str) ->[parse_error] throw;
  // ...
}

But I'm not proposing this here.

On Mon, 8 Jun 2020 at 12:05, Nikolay Mihaylov <nmmm@nmmm.nu> wrote:
Since when this compiles?

Isn't it needs {} ?

auto parse_int_square(std::string_view const str)
    -> std::tuple<int, int>
{
  auto const i = parse_int(str);
  return i, i * i; // <-------
}


On Mon, Jun 8, 2020 at 1:53 PM Toby Brull via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Hi,

I was thinking about error-handling recently (see references [1] and [2] below). Of course, there are several proposals aimed at improving the error-handling mechanisms in C++ (p0709, p1028, p1029, p1144; p0323, p0798).

I was particularly interested in p0709 (title: "Zero-overhead deterministic exceptions: Throwing values"). I would summarise this proposal here as making error-handling better by making exceptions better. My thought was that maybe one could tackle the problem of error-handling at a lower level first, and only bring exceptions into the picture later, especially given that some people don’t want to use exceptions.

So, my idea was to allow functions to have multiple, alternative return-paths at the language level. Basically, a function declaration would be allowed to declare any number of alternative return-paths (each with an associated alternative return-type). The function implementation could then return along any of those return-paths at any point in its execution. The caller of such a function would always be required to handle all alternative return-paths in some way: either (a) explicitly (e.g. by throwing an exception or handling the error otherwise) or (b) by declaring the same alternative return-path (in which case the mechanism would work similar to stack unwinding). Failure to do either (a) or (b) results in a compile-time error.

Here is a short snippet of what it might look like (inspired by [2]):

int parse_int(std::string_view const str)
    ->[parse_error] std::string
{
  std::stringstream ss; ss << str;
  int i; ss >> i;
  if (ss.fail()) {
    return[parse_error] "parse_positive_int: not an int";
  }
  else {
    return i;
  }
}

auto parse_int_square(std::string_view const str)
    -> std::tuple<int, int>
    ->[parse_error] std::string
{
  auto const i = parse_int(str);
  return i, i * i;
}

int main() {
  std::string input;
  std::cin >> input;

  auto const [i, i_sq] = parse_int_square(input)
    ->[parse_error] auto const& msg {
      std::cerr << “Error: “ << msg;
      return 1;
    };

  assert(i * i == i_sq);
  std::cout << "i_sq = " << i_sq << '\n';
  return 0;
}


More extensive brain storming here: https://github.com/TobyBrull/scratchpad/blob/master/alternative_return_paths.cpp

I imagine all this would still be compatible with p1028/std::error. It might also have other applications besides error-handling; essentially, every function that returns a std::variant could use this mechanism.

I don't have any experience working on compilers, but I imagine this should be possible to implement efficiently, although it would require an ABI extension. I imagine the alternative returns-paths to be part of the function type and thus affect name mangling.

What do you think?

Cheers,
Toby

References:
[1] http://lucteo.ro/2018/04/21/exception-exploration-2/
[2] Phil Nash's CppCon 2019 talk,
"The Dawn of a New Error" ( https://www.youtube.com/watch?v=ZUH8p1EQswA )
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals