Date: Thu, 21 Dec 2023 12:02:56 -0500
On Thu, Dec 21, 2023 at 7:39 AM Frederick Virchanza Gotham via
Std-Proposals <std-proposals_at_[hidden]> wrote:
>
>
> I see people arguing that the Lakos rule should be kept, and others saying it should be abolished.
>
> For everyone to meet half way, what if the Standard library could do:
>
> namespace std {
> int SomeFunc(int,int) noexcept_Lakos;
> }
>
> A function marked as 'noexcept_Lakos' is said to be a 'Lakos function'.
>
> So then if you want a Lakos function to be 'noexcept', you do something like:
>
> void MyFunc(int const a, int const b) noexcept
> {
> using noexcept_Lakos;
> // The above line ensures that all
> // Lakos functions called in this
> // function won't throw
> return 2 * std::SomeFunc(a,b);
> }
>
> Or if you just want to single-out one function call:
>
> void MyFunc(int const a, int const b) noexcept
> {
> return 2 * _Lakos(std::SomeFunc(a,b));
> }
OK, so let's game this out.
There are two sides to the Lakos Rule. I think others have done a good
job of explaining what the Lakos rule is for. So, for the sake of
argument, I'm going to roleplay someone who doesn't want the Lakos
rule, who *wants* these narrow contract functions to be `noexcept`.
So here's a question: why do I want those functions to "be noexcept"?
Well, it's because I don't want them throwing exceptions. But the
standard already says that the function "throws: nothing". Which means
that I, as the writer of the code using this function, can presume
that no exceptions will be emitted by it, because that would otherwise
violate the standard.
OK, but the question remains: if I already know that the function
can't throw, why do I need it to "be noexcept"?
Well, the only reason I can come up with is that I want to employ
`noexcept` as an expression. You can check to see if an expression
calls any function that isn't `noexcept`. So I want to be able to
check this and do something different if an expression isn't
`noexcept`.
Which leads to a new question: what do I want to do differently if an
expression is not `noexcept`?
There are places where `noexcept` detection matters. Move
constructors/assignment operators that are categorically `noexcept` is
important, as it may determine whether or not you can rely on movement
in a scenario where recovery from throwing an exception is a problem.
The way you code assignment operators can change based on this. See
`std::variant` and its "valueless" status.
But that's primarily about constructing elements. This is not general
purpose code; it lives in very specific, constrained circumstances.
In your above example of `using noexcept_Lakos`, what does this
actually *do*? What would it actually change or improve, relative to
not having that statement?
If the "throws: nothing" functions actually do throw (violating the
standard, BTW), your `noexcept` specifier on the function will do what
`noexcept` specifiers do. So imposing `noexcept` on those functions...
doesn't actually change any apparent behavior. What will happen is
what happens when an exception tries to exit a `noexcept` function.
The same goes for the other example: it changes nothing since the
calling function is already `noexcept`.
So the only place where this would ever be useful is if you're calling
a "Lakos noexcept" function inside a function that is not *itself*
`noexcept`. So... why would you be doing that?
Std-Proposals <std-proposals_at_[hidden]> wrote:
>
>
> I see people arguing that the Lakos rule should be kept, and others saying it should be abolished.
>
> For everyone to meet half way, what if the Standard library could do:
>
> namespace std {
> int SomeFunc(int,int) noexcept_Lakos;
> }
>
> A function marked as 'noexcept_Lakos' is said to be a 'Lakos function'.
>
> So then if you want a Lakos function to be 'noexcept', you do something like:
>
> void MyFunc(int const a, int const b) noexcept
> {
> using noexcept_Lakos;
> // The above line ensures that all
> // Lakos functions called in this
> // function won't throw
> return 2 * std::SomeFunc(a,b);
> }
>
> Or if you just want to single-out one function call:
>
> void MyFunc(int const a, int const b) noexcept
> {
> return 2 * _Lakos(std::SomeFunc(a,b));
> }
OK, so let's game this out.
There are two sides to the Lakos Rule. I think others have done a good
job of explaining what the Lakos rule is for. So, for the sake of
argument, I'm going to roleplay someone who doesn't want the Lakos
rule, who *wants* these narrow contract functions to be `noexcept`.
So here's a question: why do I want those functions to "be noexcept"?
Well, it's because I don't want them throwing exceptions. But the
standard already says that the function "throws: nothing". Which means
that I, as the writer of the code using this function, can presume
that no exceptions will be emitted by it, because that would otherwise
violate the standard.
OK, but the question remains: if I already know that the function
can't throw, why do I need it to "be noexcept"?
Well, the only reason I can come up with is that I want to employ
`noexcept` as an expression. You can check to see if an expression
calls any function that isn't `noexcept`. So I want to be able to
check this and do something different if an expression isn't
`noexcept`.
Which leads to a new question: what do I want to do differently if an
expression is not `noexcept`?
There are places where `noexcept` detection matters. Move
constructors/assignment operators that are categorically `noexcept` is
important, as it may determine whether or not you can rely on movement
in a scenario where recovery from throwing an exception is a problem.
The way you code assignment operators can change based on this. See
`std::variant` and its "valueless" status.
But that's primarily about constructing elements. This is not general
purpose code; it lives in very specific, constrained circumstances.
In your above example of `using noexcept_Lakos`, what does this
actually *do*? What would it actually change or improve, relative to
not having that statement?
If the "throws: nothing" functions actually do throw (violating the
standard, BTW), your `noexcept` specifier on the function will do what
`noexcept` specifiers do. So imposing `noexcept` on those functions...
doesn't actually change any apparent behavior. What will happen is
what happens when an exception tries to exit a `noexcept` function.
The same goes for the other example: it changes nothing since the
calling function is already `noexcept`.
So the only place where this would ever be useful is if you're calling
a "Lakos noexcept" function inside a function that is not *itself*
`noexcept`. So... why would you be doing that?
Received on 2023-12-21 17:03:07