C++ Logo


Advanced search

Re: [wg14/wg21 liaison] P2961R1 syntax for Contracts: viable for C?

From: Jens Maurer <jens.maurer_at_[hidden]>
Date: Fri, 6 Oct 2023 17:15:23 +0200
On 06/10/2023 16.53, Martin Uecker via Liaison wrote:
> But I am trying to anticipate what happens in the future: Won't people
> then simply do:
> #if ... compiler and version check ...
> #endif
> void foo(int x)
> 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?

Isn't that what you would do for any other new feature that comes along
in case you want to still support older compilers with you code?

typeof, auto, VLAs, you name it?

All of these can appear in inline functions in header files,
and either you avoid using the new features or you introduce
some (usually macro-based) abstraction around it.

Something like

#define CONTRACT_PRE(x) pre x
define CONTRACT_PRE(x)

>> 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.

A new compiler, conforming to C++next, will support contracts to their
specified extent, always. There is nothing optional about that feature.

>> 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?

Only for those people that actually do want to support older compilers,
yet want to contract-enable their code.

On my planet, C++ users would first upgrade their compiler
and then use the new features, without expectation that their
code will ever again be compiled with an older compiler.

In such a world, always unconditionally syntax-checking the
contract expressions is a win against bit-rot.
(And nobody would be using macros.)

>> You will be able to turn the actual runtime check off, so if you have `pre(expr)`, then `expr` won't be evaluated (for example in Release mode), but you won't be able to turn off the fact that `expr` is still parsed and odr-used.
>> I'm not sure if the term "odr-use" makes any sense in C but I hope you still know what I mean. The gist is that Contracts in C++ are not, and never will be, token-ignorable.
> And this is fine in theory but it will only work for
> completely new projects that start fresh with C++26 with
> a new compiler.

No, it also works for existing projects that upgrade the
shop compiler to C++26 and then gradually introduce
contracts in their codebase.

> And maybe this is just OK for a new C++ features, but I think for
> C where old code and existing projects as well as compatiblity
> across compiler and language versions is really important.
> So I think we need to plan for a transition period. And I do not see
> how you can have a transition period for a feature you can not turn
> off based on a compiler or language versions.

For all other features I know, it's on the user to create macros
if they want that kind of transition facility, not on the
language. I'm not seeing why contracts should be different
in that regard.


Received on 2023-10-06 15:15:26