Date: Fri, 6 Oct 2023 17:45:36 +0300
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.
Cheers,
Timur
> On 6 Oct 2023, at 17:30, Martin Uecker <ma.uecker_at_[hidden]> 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_at_[hidden]> 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 be
> usefully be added to an existing codebase incrementally. That
> does 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 for
> C could be to make the code acceptable to older compilers that do
> not 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 would
> be an option, but if we want to transition to "pre" this would still
> be 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 the
> keywords specially.
>
> So there is no fundamental problem with this syntax. It is just that
> it is not really designed for a feature that can be phased in gradually
> into existing code. But this is exactly how contracts would be most
> useful 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
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.
Cheers,
Timur
> On 6 Oct 2023, at 17:30, Martin Uecker <ma.uecker_at_[hidden]> 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_at_[hidden]> 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 be
> usefully be added to an existing codebase incrementally. That
> does 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 for
> C could be to make the code acceptable to older compilers that do
> not 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 would
> be an option, but if we want to transition to "pre" this would still
> be 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 the
> keywords specially.
>
> So there is no fundamental problem with this syntax. It is just that
> it is not really designed for a feature that can be phased in gradually
> into existing code. But this is exactly how contracts would be most
> useful 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
Received on 2023-10-06 14:45:39