Skip to content

[SUGGESTION] safe exception handling - compile functions as noexcept by default #361

Closed
@robertefry

Description

@robertefry

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.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions