In C++, even if we go with the "function-like" P2961 syntax, we can't make contracts always look like function-like macros. Yes, the most basic contracts indeed look syntactically like function calls or function-like macros:
pre (x != 0)
Then we have postconditions that name the return value. This already doesn't look like a function call anymore because of the colon. Maybe this still qualifies as valid function-like macro syntax? I'm not sure:
post (ret: ret != 0)
And then we have a number of extensions which we already know we want to standardise for C++ after we get the initial, basic version through (which we call the "Contracts MVP"). All of these post-MVP extensions are *not* compatible with function-like macro syntax.
For example, we need the ability to annotate a contract with multiple labels simultaneously. The exact syntax is to be decided, but if we go for P2961 rather than P2935 then it could be something like
pre <audit, new> (x != 0)
or perhaps
pre (x != 0) [audit, new]
In any case, you cannot absorb these labels into a single keyword and make the whole thing functional-macro-like, unless you want a combinatorial explosion of keywords.
We will further have labels that take parameters, such as
pre <audit_level(3)> (x != 0)
There is no way to do this with a function-like macro syntax as far as I can see.
And then we want to introduce captures for contracts, which would work similar to lambda captures. They allow you to do things like "remembering" a value at the point when the function begins and then use that value in a postcondition that is evaluated when the function returns, for example
void increment_size()
post [old_size = size()] (size() == old_size + 1);
There are more such planned extensions; if you're curious, please check out
P2755.
Perhaps, for C you will never want to adopt any of these extensions, and that's fine. But I think it's important to mention that at least in C++, they will come. Having a syntax for contracts that is fully compatible with function-like macro syntax is therefore just as much a non-goal for us as having a syntax for contracts that is fully compatible with attribute syntax, or having a syntax for contracts that is compatible with any other existing feature. That's not what we're going for in C++. Contracts are a new language feature and like any new language feature they will have a new, not backwards-compatible syntax in C++, one way or another (whether we adopt P2935 or P2961). The only question here — why I started this thread — is which of these syntaxes would create fewer problems for C.
Hope that makes sense?
Please let me know if you have any further thoughts on this. Thanks!
Cheers,
Timur
On 6 Oct 2023, at 21:40, Martin Uecker <ma.uecker@gmail.com> wrote:
Am Freitag, dem 06.10.2023 um 14:14 -0400 schrieb Aaron Ballman:On Fri, Oct 6, 2023 at 2:00 PM Martin Uecker <ma.uecker@gmail.com> wrote:
Am Freitag, dem 06.10.2023 um 13:57 -0400 schrieb Aaron Ballman via Liaison:
On Fri, Oct 6, 2023 at 12:56 PM Timur Doumler <cpp@timur.audio> wrote:
OK, thanks, I understand that argument now.
I am not sure though if it makes much sense to design our syntax around that, given that we *already* know we can't (and don't want to) achieve this kind of seamless backwards-compatibility in C++, and by extension in any code shared between C and C++, so only codebases in pure C would benefit from such a possibility. And you won't get backwards-compatibility with older compilers, only with newer compilers in "old standard" mode, because every existing compiler I'm aware of rejects the colon between [[...]] as a syntax error today.
However, my understanding is that with either of the syntax proposals, we would be able to achieve backwards-compability with older compilers via wrapping the whole feature in macros, in exactly the same way we do for other new features that add new syntax.
I am really interested whether anyone here has a preference for one syntax and against the other for any other reason that does *not* have to do with ignorability?
I strongly prefer the syntax that looks like a function-like macro
over the syntax that looks like an attribute. I think it eases
portability, especially when compiling newer source code with an older
implementation. I don't think we should be making the user scan for
whether there's one colon or two colons to know what language feature
they're using. I think constructs like lambdas can already look quite
noisy with their balanced delimiters and this introduces another
instance of that. Also, it helps this confusion by making it more
visually distinct:
void func(int i) <Which comes first: type attributes or contracts?>;
While users still need to know which order to put things in because we
don't allow interleaving there, at least they're not trying to
remember how to order two things both using [[]] syntax.
I think function-like macros were not proposed. But I would also
prefer this.
Heh, sorry for being unclear, I didn't mean to imply it was actually a
function-like macro under the hood. I meant `pre(operand)` where the
syntax looks like a function call or function-like macro invocation.
Yes, I was also not clear. I think it would be fine if itis fixed to always be like a function-like macro and not have the [] <> prefixed versions, and it it ideallyhad a longer name that we can make a true keyword later. Martin
~Aaron
Martin
~Aaron
Cheers,
Timur
On 6 Oct 2023, at 19:35, Jens Maurer <jens.maurer@gmx.net> wrote:
On 06/10/2023 18.32, Timur Doumler wrote:
On 6 Oct 2023, at 19:28, Jens Maurer <jens.maurer@gmx.net> wrote:
If that is indeed the case, then the attribute-like syntax for Contracts would not be ignorable in C, either.
Right, but the argument is that implementations can add the small extension
to parse-ignore ":" in that spot right now, and then be future-proof for
ignoring future attribute-like contracts.
Right. Yes, I can follow that argument. But that begs the question: what is so special or different about Contracts that you want this feature in particular to be backwards-compatibly-ignorable by older compilers, considering that we don't do that for any other new language feature where we add new syntax to the language?
The argument, as far as I understand, is that contracts in particular are well
suited to be retrofitted on existing code bases that need to be compatible
with older compilers / language versions.
For any other new language feature, you can just choose to ignore it for your
meant-to-be-compatible code base. But contracts are so valuable to find
bugs in existing software, so you want them everywhere ASAP.
(I'm just repeating an argument I think I heard. This is not my opinion.)
Jens
_______________________________________________
Liaison mailing list
Liaison@lists.isocpp.org
Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/liaison
Link to this post: http://lists.isocpp.org/liaison/2023/10/1274.php