Closed
Description
C++ assumes any function can throw, unless it is declared noexcept
. This leads to use cases where a function throws an exception yet the caller is unaware. Since exceptions are (ahem) exceptional, they should be handled imediately, or at least consciously passed up the call stack.
Instead, I propose that we declare functions as noexcept
by default, and add a new keyword throws
which will allow the function to throw an exception. Having done this, we can now enforce the calling function be either marked throws
as well, or must catch the thrown exception, adding to readability and toolability.
twice: (x: int) -> int { return 2 * x; }
// compiles to
[[nodiscard]] auto twice(int x) noexcept -> int { return 2 * x; }
approx_sqrt: (x: float) throws -> float =
{
if ( x < 0 )
throw std::invalid_argument{"cannot square-root a negative non-complex number"};
return std::sqrt(x);
}
// compiles to
[[nodiscard]] auto approx_sqrt(float x) -> float
{
if ( x < 0 )
throw std::invalid_argument{"cannot square-root a negative non-complex number"};
return std::sqrt(x);
}
// should fail to compile, f1 is not marked throws
f1: () = { throw std::runtime_error{"demonstration of an exception"}; }
// compiles, f2 is marked throws
f2: () throws = { throw std::runtime_error{"demonstration of an exception"}; }
// should fail to compile, not marked throws nor catches exceptions
g1: () =
{
f2(); // throws, not handled :(
}
// compiles because g2 is declared throws
g2: () throws =
{
f2(); // thrown exception is passed up the call stack :)
}
// compiles because g3 catches the thrown exception
g3: () =
{
try {
f2(); // throws
} catch (std::runtime_error const& e) {
std::cerr << e.what(); // catch it, so we can continue execution :)
}
}
I suggest const
and noexcept
functions be implemented before this feature is added, since it shares common syntax.