cplusplus / draft

C++ standards drafts
http://www.open-std.org/jtc1/sc22/wg21/
5.66k stars 748 forks source link

Missing "<condition> is `true`|`false`" #4713

Open tkoeppe opened 3 years ago

tkoeppe commented 3 years ago

In [utilities]. we say things like "get() == nullptr." a lot instead of "get() == nullptr is true." in many places.

We should decide whether we want to demand a specific style, and if so, document that style and fix the existing text.

ViralTaco commented 3 years ago

TL;DR: In my opinion, adding "is true" doesn't clarify the subtext.

(expr == nullptr) means that evaluating expr results in a nullptr value, i.e.: it doesn't represent of valid pointer, as far as I understand (near). It's strictly equivalent to not expr which, in-turn, is equivalent to not (expr != nullptr) "not not equal is, by definition, equal"

jensmaurer commented 3 years ago

Recently, we have preferred "expression is true". The argument is that expression alone does not form a grammatical English sentence. If we say "Preconditions: get() != nullptr", that's probably valid C++, but not English. Further, the idea is that the "is" asks for evaluation of the expression, not just its well-formedness or similar aberrations.

ViralTaco commented 3 years ago

"expression is true" is, arguably, no closer from forming a "grammatical English sentence". I read == as "is equal to" and != as "is not equal to". 'A is equal to B' is 'true'. That's not better for me. I understand what you're saying. I just disagree.

jwakely commented 3 years ago

I read == as "is equal to"

But when it appears in code, it's an expression that may or may not be true. Otherwise, the third operand of x == y ? op2 : op3 would never be evaluated, and if (x == y) {} else {} would never take the else branch. C++ is not mathematics, and the == operator is a predicate, not an assertion.

The core of the issue is that [structure.requirements] p4 says "Requirements are stated in terms of well-defined expressions that define valid terms of the types that meet the requirements." So if the spec just says "Preconditions: get() != nullptr." then all we're requiring is for the expression to compile and have a well-defined value (so get() doesn't return an indeterminate value or invalid pointer). There would be no requirement for it to have a particular result (true or false). It's not about how you read the wording; the standard defines its terminology and conventions, and so it needs to follow them.

We should decide whether we want to demand a specific style, and if so, document that style and fix the existing text.

We could consider blanket wording that says when we use a conditional-expression in a Constraints:, Mandates:, or Preconditions: element, that we mean it has to be true. If we say that's what it means, then that's what it means. The problem is that today we don't say it, so we need the explicit "is true" and "is false" wording everywhere.

If we don't add something saying that, then I think we do need to add the missing "is true" cases in [utilities] and elsewhere.

ViralTaco commented 3 years ago

Oh… 🤔 Ok, I get it now. (Took time) However, in “is true” wouldn't you agree that “is” feel like it refers to an identity, and not a value? 🧐 Does "evaluate" fit in there?

So if the spec just says "Preconditions: get() != nullptr." then all we're requiring is for the expression to compile and have a well-defined value

Ok, I underestimated the gravity of the situation. How about “Evaluation of the expression get() != nullptr produces the value true”, or maybe “get() != nullptr shall be true”.

I'll agree with “is” if everyone believes “is” is fine. What is is is urgent 😎

CaseyCarter commented 3 years ago

The core of the issue is that [structure.requirements] p4 says "Requirements are stated in terms of well-defined expressions that define valid terms of the types that meet the requirements." So if the spec just says "Preconditions: get() != nullptr." then all we're requiring is for the expression to compile and have a well-defined value (so get() doesn't return an indeterminate value or invalid pointer). There would be no requirement for it to have a particular result (true or false). It's not about how you read the wording; the standard defines its terminology and conventions, and so it needs to follow them.

[structure.specifications]/3.3 says that "Preconditions" specify "the conditions that the function assumes to hold whenever it is called; violation of any preconditions results in undefined behavior." If get() != nullptr is a "condition that must hold", I don't think there's much danger of someone misreading that to imply anything other than that get() != nullptr must evaluate to true.

tkoeppe commented 3 years ago

It may be that expressions involving == or != would be clear enough, but we have other kinds of expressions, too, where embedding them in an English phrase improves clarity. A uniform style of always writing a complete English phrase is thus simple and effective, and the "is true" wording is short enough to not get in the way. I don't see a strong reason to change this, or any serious fault with it.

Yes, we could have blanket wording, but blanket wording comes at a price, too, and I'm not convinced it would improve matters here.

jensmaurer commented 3 years ago

How about “Evaluation of the expression get() != nullptr produces the value true”,

That's lengthy.

or maybe “get() != nullptr shall be true”.

We want to avoid "shall" because it makes for worse overall reading pleasure.

So, "shall be" -> "is", and we are at the status quo.

tkoeppe commented 2 years ago

Editorial meeting consensus: We would like to adopt the "is true" style generally. We will add it to the wiki and update the non-conforming places.