Am Freitag, dem 06.10.2023 um 17:45 +0300 schrieb Timur Doumler:
Hi Martin,
That's interesting, thanks. It is important to note that in C++, neither of the candidate syntaxes is backwards-compatible in the way you describe. The attribute-like P2935 syntax is:
[[ pre : expression ]]
[[ post optional-name-for-return-value : expression ]]
[[ assert : expression ]]
That does not follow the standard attribute grammar, which in C++ is:
[[ attribute-token ]]
[[ attribute-token ( parameter-clause ) ]]
because the colon is not allowed in standard attribute grammar. So in C++, even if we choose P2935 (the attribute-like syntax), a pre-Contracts compiler is still *required* to diagnose a syntax error if it sees a contract. That's why we call P2935 the attribute-*like* syntax, it's *like* an attribute because it has [[ ... ]] , but isn't actually an attribute because it doesn't follow attribute grammar.
So for C++, the option to have a backwards-compatible syntax isn't even on the table anymore (we discussed this option in SG21 – it would require us to put parentheses around the expression and would forbid having anything between the pre/post/assert and that parenthesised expression – and that's just too limiting for this feature) so it's simply not a consideration for us.
I understand that in C, the situation is different because you're allowed to token-ignore anything between [[ ... ]] even if it features a colon.
I am not entirely sure. In practice compilers also fail to process this.
And, yes, exactly for this reason, I actually believe that attributes would have been
the best choice for C.
But I think P2935 would still be ok because only a minor changes to compilers
would be required to make this work. If it is clear that contracts with such
syntax are likely to come, people could make these changes now to reduce
issues later.
Martin
Cheers,
Timur
On 6 Oct 2023, at 17:30, Martin Uecker <ma.uecker@gmail.com> wrote:
Am Freitag, dem 06.10.2023 um 09:40 +0300 schrieb Ville Voutilainen:On Fri, 6 Oct 2023 at 08:31, Martin Uecker <ma.uecker@gmail.com> wrote:
To be honest, I think it is a mistake also for C++. I believe
that even for C++ people will end up trying to introduce this into
existing code and then are forced to make it ignorable by wrapping it
into #ifdef or macros. The end result would neither be nice
nor ignorable.
Sure, but that's no different from conditionally adopting any other
new language facility that
the older implementations don't recognize. Which for C++ is almost
every new language facility.
We have standardized feature-detection macros, even, to help with
preprocessor-based conditional
migration.
The difference is that this seems to be a feature which could beusefully be added to an existing codebase incrementally. Thatdoes not make too much sense for every new feature.
It wouldn't cause me loss of sleep if C compilers were allowed to
completely ignore a contract annotation.
Fixing syntax errors when using a compiler that doesn't ignore them is
compatible with compilers that would
ignore the annotations.
Right. And especially in a context where headers are shared, the
scenario that for some transition time (probably decades) the code
needs be processed also by compilers not supporting contracts seems
very likely.
For C I think it would be important to have a syntax that is ignorable.
Just to make sure I understand.. in effect, to make the feature
optional? So as to not hoist
its burden on implementations that don't want it?
No, I would make it mandatory for new C versions. But a useful goal forC could be to make the code acceptable to older compilers that donot have full support for it during a transition time without needing preprocessor wrappers.
A syntax as proposed here (it seems, correct me if I am wrong) such
as:
void f(int x)
pre <audit> (x > 0);
would be a pretty bad choice for C.
The <audit> part is at this point hypothetical. I'm curious why you
think that's a bad choice.
One problem is introducing a three letter keyword. Yes, _Pre wouldbe an option, but if we want to transition to "pre" this would stillbe a problem later. The next problem is that this syntax can not be hidden behind a macro.This would work for:_Pre (<audit>, (x > 0))Also some attribute-like mechanism would work[[ __pre__ (x > 0) ]]where the parsing context could allow a compiler to treat thekeywords specially.So there is no fundamental problem with this syntax. It is just thatit is not really designed for a feature that can be phased in graduallyinto existing code. But this is exactly how contracts would be mostuseful in C: By enhancing existing code step by step.If I understand things correctly, it's novel for C to have function
parameters be in scope
after leaving a function declarator and before a function definition
begins. In C++, that hasn't
been novel for ages, with trailing return types,
noexcept-specifications, and constraints all
using function parameters.
This is also true, but I think this is not a major issue.Martin