Date: Sun, 5 Oct 2025 20:49:53 +0200
On Sun, Oct 5, 2025 at 8:15 PM Andrzej Krzemienski via SG15 <
sg15_at_[hidden]> wrote:
> Hi All,
> While I wait for the feedback from the authors of P3835 below, let me
> share a different example that puzzles me. Imagine a three-file scenario.
>
> // lib1.hpp
> // -----
> bool is_calibrated(shared_ptr<Tool> const& t)
> pre (t != nullptr);
> // -----
>
> // Lib2.hpp
> // ----
> void work(shared_ptr<Tool>& t)
> pre(is_calibrated(t));
> // ----
>
> // Main.cpp
> // ----
> work(t);
> // ----
>
> If I somehow manage to configure my build chain to runtime-check
> preconditions of the library lib2, does this mean that the assertion `t !=
> nullptr` will be checked or not? The assertion as well as function
> is_calibrared is defined in a different library that I am not
> runtime-assertion-checking. Such a combination of preconditions seems
> plausible: the author of `work()` can assume that predicates in contract
> assertions can themselves have narrow contacts, and that preconditions of
> preconditions apply recursively. And this is true; but it is not clear
> how the selective runtime-checking enablement works in that case.
>
> I do not think it should be left to implementations. I think the Standard
> should guarantee that if an assertion predicate is evaluated using the
> `enforce` mode, the preconditions of functions called in that predicate are
> also evaluated in `enforce` mode. But I am not sure if this is
> implementable. This gets even more interesting with `observe` mode.
>
That breaks with adding new checks that may not work. If you enforce
everything inside an enforce, then you will break if you ever edit the code
in there and make a mistake, even if you want to just observe to see if it
holds. That's the whole point of observe.
> The scenario that I am familiar with is that when a program P uses a
library L, it is likely that P will use L incorrectly, and additional
measures need to be taken to test if P is using L correctly. This would
mean that in the P2900 world we would want to runtime check the assertions
*at the library boundary* but not necessarily *inside* the library. IOW, If
I were the author of P, I would trust library L that it was
thoroughly tested, and would not want to assertion-test its implementation.
But I would like to test if I am *using* the library correctly. So I would
like to enable every precondition in L's interface and some contract_asset
statements close to library entry points that also function as
preconditions. But only those. If libstdc++'s STL implementation offers
control macros to enable STL-specific assertions, those assertions
practically check if the user is using the STL correctly: not if STL has
been correctly implemented.
Part of the solution for this is P3400, which allows you to define labels
like "libfoo_interface" and "libfoo_internal" which would be your handles
to configure those checks separately as you please.
If there is no relevant overhead from leaving contract checks enabled,
would you actually care if "libfoo_internal" was enabled or disabled?
sg15_at_[hidden]> wrote:
> Hi All,
> While I wait for the feedback from the authors of P3835 below, let me
> share a different example that puzzles me. Imagine a three-file scenario.
>
> // lib1.hpp
> // -----
> bool is_calibrated(shared_ptr<Tool> const& t)
> pre (t != nullptr);
> // -----
>
> // Lib2.hpp
> // ----
> void work(shared_ptr<Tool>& t)
> pre(is_calibrated(t));
> // ----
>
> // Main.cpp
> // ----
> work(t);
> // ----
>
> If I somehow manage to configure my build chain to runtime-check
> preconditions of the library lib2, does this mean that the assertion `t !=
> nullptr` will be checked or not? The assertion as well as function
> is_calibrared is defined in a different library that I am not
> runtime-assertion-checking. Such a combination of preconditions seems
> plausible: the author of `work()` can assume that predicates in contract
> assertions can themselves have narrow contacts, and that preconditions of
> preconditions apply recursively. And this is true; but it is not clear
> how the selective runtime-checking enablement works in that case.
>
> I do not think it should be left to implementations. I think the Standard
> should guarantee that if an assertion predicate is evaluated using the
> `enforce` mode, the preconditions of functions called in that predicate are
> also evaluated in `enforce` mode. But I am not sure if this is
> implementable. This gets even more interesting with `observe` mode.
>
That breaks with adding new checks that may not work. If you enforce
everything inside an enforce, then you will break if you ever edit the code
in there and make a mistake, even if you want to just observe to see if it
holds. That's the whole point of observe.
> The scenario that I am familiar with is that when a program P uses a
library L, it is likely that P will use L incorrectly, and additional
measures need to be taken to test if P is using L correctly. This would
mean that in the P2900 world we would want to runtime check the assertions
*at the library boundary* but not necessarily *inside* the library. IOW, If
I were the author of P, I would trust library L that it was
thoroughly tested, and would not want to assertion-test its implementation.
But I would like to test if I am *using* the library correctly. So I would
like to enable every precondition in L's interface and some contract_asset
statements close to library entry points that also function as
preconditions. But only those. If libstdc++'s STL implementation offers
control macros to enable STL-specific assertions, those assertions
practically check if the user is using the STL correctly: not if STL has
been correctly implemented.
Part of the solution for this is P3400, which allows you to define labels
like "libfoo_interface" and "libfoo_internal" which would be your handles
to configure those checks separately as you please.
If there is no relevant overhead from leaving contract checks enabled,
would you actually care if "libfoo_internal" was enabled or disabled?
Received on 2025-10-05 18:50:11