Date: Fri, 6 Oct 2023 18:16:10 +0300
Hi Martin,
> On 6 Oct 2023, at 17:53, Martin Uecker <ma.uecker_at_[hidden]> wrote:
> Ok, thanks! This makes sense.
>
> But I am trying to anticipate what happens in the future: Won't people
> then simply do:
>
> #if ... compiler and version check ...
> #define CONTRACTS_SUPPORTED
> #endif
>
> void foo(int x)
> #ifdef CONTRACTS_SUPPORTED
> pre ( x > 0)
> #endif
>
> This code is then "ignorable" and will be ignored by older compilers
> and in that case nothing is even parsed or odr-used.
>
> One can say, this is then the user fault, but what other choice do you
> have in reality if you need to support different compilers and versions?
Yes. In C++, we have feature test macros for this. There will be a macro defined in the C++ Standard called `__cpp_has_contracts` which you can use to do the above. This is what we do for every new language feature. In this case, of course the design goal of "you can't branch on whether contract checks are turned off" won't hold, but that's fine, because it's not the default – the user chose to opt into that explicitly by using macros.
>
>> And an explicit goal of Contracts – the main purpose of which is to detect bugs – is that you should never be able to branch on whether a contract is checked or ignored, because then you could have a bug that cannot be detected by a Contract check – the bug is there when Contracts are off, but as soon as you switch them on to find the bug, your program takes a different branch where the bug is not present, and the bug disappears. We want to make this impossible by design.
>
> This makes sense, but I do not get the connection to "ignorable".
> The #ifdef above would encourage compile-time checks
> based on support for contracts.
The verb "ignorable" is overloaded here. There are two meanings: "ignorable" at compile time – macro everything out – and "ignorable" in the contract sense: the contract predicate is parsed as an expression and odr-used, but not evaluated/checked at runtime.
>
>> Therefore you won't be able to do with C++ Contracts what you can do with macro assert in <cassert> today: define NDEBUG and have all the assert macros token-ignored. We want to explicitly ban that case.
>
> Yes, but are you not just forcing people to do exactly this by
> creating a syntax they have to put into a preprocessor wrapper?
If you want backwards-compatibility, then yes. But this is not different to any other new C++ feature where we added a new annotation-like thing to a C++ function declaration: `noexcept` , `constexpr`, `requires` clauses... none of these things are backwards-compatible either, you have to macro them out if you're using an older compiler. I don't really see a problem with that, or any reason why Contracts would be special and different.
Cheers,
Timur
> On 6 Oct 2023, at 17:53, Martin Uecker <ma.uecker_at_[hidden]> wrote:
> Ok, thanks! This makes sense.
>
> But I am trying to anticipate what happens in the future: Won't people
> then simply do:
>
> #if ... compiler and version check ...
> #define CONTRACTS_SUPPORTED
> #endif
>
> void foo(int x)
> #ifdef CONTRACTS_SUPPORTED
> pre ( x > 0)
> #endif
>
> This code is then "ignorable" and will be ignored by older compilers
> and in that case nothing is even parsed or odr-used.
>
> One can say, this is then the user fault, but what other choice do you
> have in reality if you need to support different compilers and versions?
Yes. In C++, we have feature test macros for this. There will be a macro defined in the C++ Standard called `__cpp_has_contracts` which you can use to do the above. This is what we do for every new language feature. In this case, of course the design goal of "you can't branch on whether contract checks are turned off" won't hold, but that's fine, because it's not the default – the user chose to opt into that explicitly by using macros.
>
>> And an explicit goal of Contracts – the main purpose of which is to detect bugs – is that you should never be able to branch on whether a contract is checked or ignored, because then you could have a bug that cannot be detected by a Contract check – the bug is there when Contracts are off, but as soon as you switch them on to find the bug, your program takes a different branch where the bug is not present, and the bug disappears. We want to make this impossible by design.
>
> This makes sense, but I do not get the connection to "ignorable".
> The #ifdef above would encourage compile-time checks
> based on support for contracts.
The verb "ignorable" is overloaded here. There are two meanings: "ignorable" at compile time – macro everything out – and "ignorable" in the contract sense: the contract predicate is parsed as an expression and odr-used, but not evaluated/checked at runtime.
>
>> Therefore you won't be able to do with C++ Contracts what you can do with macro assert in <cassert> today: define NDEBUG and have all the assert macros token-ignored. We want to explicitly ban that case.
>
> Yes, but are you not just forcing people to do exactly this by
> creating a syntax they have to put into a preprocessor wrapper?
If you want backwards-compatibility, then yes. But this is not different to any other new C++ feature where we added a new annotation-like thing to a C++ function declaration: `noexcept` , `constexpr`, `requires` clauses... none of these things are backwards-compatible either, you have to macro them out if you're using an older compiler. I don't really see a problem with that, or any reason why Contracts would be special and different.
Cheers,
Timur
Received on 2023-10-06 15:16:14