Conditional operator as a statement
-
In a post just made by someone here they use the following as a statement:
(docType == SW::FACTURA) ? setLabelText("Factura") : setLabelText("Boleta");
I have not tried this in any compilers to see if they have anything to say, and I do not know which compiler the OP is using. But:
-
How "OK" or "not OK" is this regarded by the C++ community? I would never use it as a statement, and I do not recall ever seeing it used as such in any C++ code I have seen over the years.
-
Furthermore, I know compilers demand that each side of the
:
return the same type in a conditional operator. But heresetLabelText()
is (presumably)void
, isn't that a return type which is not acceptable in a? :
?
P.S.
Before anyone says, of course here I would write this assetLabelText(docType == SW::FACTURA ? "Factura" : "Boleta");
but that is not the point of my question. The OP could also have had different function calls in the statement, like:
(a == b) ? someFunc() : otherFunc();
-
-
If there's a doubt there's no doubt.
That's a weird line of code that makes you double check it to be sure you understood correctly, thus it should be avoided.
-
I saw this idiom some times but not often. It's not wrong but not very common.
btw: I've a similar statement in python where I sa a c++ programmer always have to thunk about it:
a = 3 if b == 4 else 5
-
I saw this idiom some times but not often. It's not wrong but not very common.
btw: I've a similar statement in python where I sa a c++ programmer always have to thunk about it:
a = 3 if b == 4 else 5
@Christian-Ehrlicher
I agree I don't like the syntax/ordering/layout of the Pythonif else
operator. For one thing I don't like how your eye has to go to pick out the possible values of3
or5
fora
, one near the beginning while the other is at the end. The Python statement is the same as the C++ conditional operator written as:a = (b == 4) ? 3 : 5;
But you cannot use the Python
if else
on its own as a complete statement as just3 if b == 4 else 5 someFunction() if b == 4 else anotherFunction()
where we are comparing against the poster who has used C++
? :
as a standalone statement. -
it's fine, you don't necessarily need to have the same return type either.
int i = 1; double d = 2.5; auto x = cond ? i : d; // -> double
is totally legit. But it may produce compiler warnings, if the appropriate compiler flag are enabled (-Wconversion, -Wsign-conversion, -Wfloat-conversion etc) and its applicable
-
it's fine, you don't necessarily need to have the same return type either.
int i = 1; double d = 2.5; auto x = cond ? i : d; // -> double
is totally legit. But it may produce compiler warnings, if the appropriate compiler flag are enabled (-Wconversion, -Wsign-conversion, -Wfloat-conversion etc) and its applicable
@J.Hilk said in Conditional operator as a statement:
is totally legit.
Only because
int
is "promotable" todouble
. They do not have to the same return type but they at least have to have promotable/convertible return types.The (academic) question is whether that is enforced by the
? :
operator itself or whether it is only enforced on (say) assignment of the result to a variable or usage in a condition. The situation we are discussing is the (peculiar):a ? b() : c();
as a statement, so the result is never used. I still imagine it's the
:
operator which demands the type compatibility even if the result is not used.BTW (I just discovered) the "Standard" says something along these lines:
5.17/3
If the second and third operand have different types, and either has (possibly cv-qualified) class type, an attempt is made to convert each of those operands to the type of the other. The process for determining whether an operand expression E1 of type T1 can be converted to match an operand expression E2 of type T2 is defined as follows:
and then, of course, loads of cases.....
-
@J.Hilk said in Conditional operator as a statement:
is totally legit.
Only because
int
is "promotable" todouble
. They do not have to the same return type but they at least have to have promotable/convertible return types.The (academic) question is whether that is enforced by the
? :
operator itself or whether it is only enforced on (say) assignment of the result to a variable or usage in a condition. The situation we are discussing is the (peculiar):a ? b() : c();
as a statement, so the result is never used. I still imagine it's the
:
operator which demands the type compatibility even if the result is not used.BTW (I just discovered) the "Standard" says something along these lines:
5.17/3
If the second and third operand have different types, and either has (possibly cv-qualified) class type, an attempt is made to convert each of those operands to the type of the other. The process for determining whether an operand expression E1 of type T1 can be converted to match an operand expression E2 of type T2 is defined as follows:
and then, of course, loads of cases.....
@JonB I was going to suggest including a link to the relevant standard section, but attempting to do so myself isn't producing satisfactory results.
https://github.com/cplusplus/draft/blob/main/source/expressions.tex#L7819 for the picky,
https://en.cppreference.com/w/cpp/language/operator_other.html for the less patient. -
@JonB I was going to suggest including a link to the relevant standard section, but attempting to do so myself isn't producing satisfactory results.
https://github.com/cplusplus/draft/blob/main/source/expressions.tex#L7819 for the picky,
https://en.cppreference.com/w/cpp/language/operator_other.html for the less patient. -
It is syntactically correct (just an expression of type void), but it's a case of what I would call "clever code" (not a compliment). It lessens readability and kinda hides the real action in a side effect of an operator for the sake of... yeah, being clever I guess, as it's not even shorter or anything.
Another example of this I've seen is the "clever" use of comma operator:
std::cout << calculate42(), calculate43();
Without looking it up - do you remember what gets printed? -
It is syntactically correct (just an expression of type void), but it's a case of what I would call "clever code" (not a compliment). It lessens readability and kinda hides the real action in a side effect of an operator for the sake of... yeah, being clever I guess, as it's not even shorter or anything.
Another example of this I've seen is the "clever" use of comma operator:
std::cout << calculate42(), calculate43();
Without looking it up - do you remember what gets printed?@Chris-Kawa said in Conditional operator as a statement:
Without looking it up - do you remember what gets printed?
,
operator returns value to right of it, so I would expect to see 1 more than the answer to Life, The Universe & Everything :)You can, of course, also implement simple
if then else
statements with&&
and||
:x && xIsTrue(); x || xIsFalse(); x && xIsTrue() || xIsFalse();
-
@Chris-Kawa said in Conditional operator as a statement:
Without looking it up - do you remember what gets printed?
,
operator returns value to right of it, so I would expect to see 1 more than the answer to Life, The Universe & Everything :)You can, of course, also implement simple
if then else
statements with&&
and||
:x && xIsTrue(); x || xIsFalse(); x && xIsTrue() || xIsFalse();
@JonB said in Conditional operator as a statement:
, operator returns value to right of it, so I would expect to see 1 more than the answer to Life, The Universe & Everything :)
Gotcha! :) Operator , has lower precedence than operator <<.
-
@JonB said in Conditional operator as a statement:
, operator returns value to right of it, so I would expect to see 1 more than the answer to Life, The Universe & Everything :)
Gotcha! :) Operator , has lower precedence than operator <<.
@Chris-Kawa said in Conditional operator as a statement:
Gotcha! :) Operator , has lower precedence than operator <<.
Ridiculous! I do not acknowledge
<<
"stream" as a decent operator! Does that have different precedence than the only respectable<<
shift-left operator? :) -
With stream and shift operators it's like with right and left angles.
They're really the same thing (wink wink, nudge nudge). -
It is syntactically correct (just an expression of type void), but it's a case of what I would call "clever code" (not a compliment). It lessens readability and kinda hides the real action in a side effect of an operator for the sake of... yeah, being clever I guess, as it's not even shorter or anything.
Another example of this I've seen is the "clever" use of comma operator:
std::cout << calculate42(), calculate43();
Without looking it up - do you remember what gets printed?@Chris-Kawa said in Conditional operator as a statement:
It is syntactically correct (just an expression of type void), but it's a case of what I would call "clever code" (not a compliment).
I would say, in general this has several caveats:
- It works in this case (as described in the OP) because both functions return void.
- If they don't return void (but the same type), there might be a [[maybe_unused]] needed depending on compiler flags.
- If they return incompatible types this doesn't work. (This makes it a programming pattern that cannot always be applied.)
For me, it has too many caveats. It's bad for teachability (which to the C++ standards committee is important).
It is also one of the use cases for this operator that is not taught. In theory, every C and C++ programmer should be able to figure this out, but it is certainly not beginner friendly. Code is meant to be written once (or at least very few times) but read several times. This will certainly break the reading flow for programmers on every experience level because it is so unusal.
The general rule is to never user
?:
, but to use regularif
/else
instead. There are a few corner cases where this is still acceptable. This mostly has to do with initialization. It is kind of unavoidable withconst
variables (though, there is a workaround with immediately invoked lambdas):const auto myvar = someBool ? 0 : 1;
But, even without
const
we would otherwise have initialization + copy if we are usingif
/else
. The same is true for the OP example:setLabelText(docType == SW::FACTURA ? "Factura" : "Boleta");
In this case the
QString
constructor will only be called for one of the strings.To answer the initial question: I don't think this is acceptable in the broader C++ community.
-
@Chris-Kawa said in Conditional operator as a statement:
It is syntactically correct (just an expression of type void), but it's a case of what I would call "clever code" (not a compliment).
I would say, in general this has several caveats:
- It works in this case (as described in the OP) because both functions return void.
- If they don't return void (but the same type), there might be a [[maybe_unused]] needed depending on compiler flags.
- If they return incompatible types this doesn't work. (This makes it a programming pattern that cannot always be applied.)
For me, it has too many caveats. It's bad for teachability (which to the C++ standards committee is important).
It is also one of the use cases for this operator that is not taught. In theory, every C and C++ programmer should be able to figure this out, but it is certainly not beginner friendly. Code is meant to be written once (or at least very few times) but read several times. This will certainly break the reading flow for programmers on every experience level because it is so unusal.
The general rule is to never user
?:
, but to use regularif
/else
instead. There are a few corner cases where this is still acceptable. This mostly has to do with initialization. It is kind of unavoidable withconst
variables (though, there is a workaround with immediately invoked lambdas):const auto myvar = someBool ? 0 : 1;
But, even without
const
we would otherwise have initialization + copy if we are usingif
/else
. The same is true for the OP example:setLabelText(docType == SW::FACTURA ? "Factura" : "Boleta");
In this case the
QString
constructor will only be called for one of the strings.To answer the initial question: I don't think this is acceptable in the broader C++ community.
@SimonSchroeder said in Conditional operator as a statement:
The general rule is to never user ?:, but to use regular if/else instead.
Hi Simon. I always read your posts with interest. To be 100% clear, you are not speaking about using
? :
in general in its normal "expression-result" context are you? You have no problem with e.g.variable = b ? x() : y();
, do you? Only with using it as a statement,b ? x() : y();
, right? Where we are indeed all agreeing this is not a "recommended" construct.Reading through the C++ standard now I come across two apparently legitimate uses of
? :
which are surprising to me at least, and germane to this thread.First, they spend time discussing what to do when either side of the
:
is of typevoid
. Which I cannot see as usable in any context where the expression result is used (e.g. assignment to variable or in anif
condition). This only makes sense (to me) in statementcond ? voidFunc() : voidFunc2();
Second, they further comment on the result of the
:
being potentially an lvalue rather than the typical rvalue one would expect. This only makes sense (to me) in statement(x ? y : z) = 42;
which perhaps surprisingly is apparently legitimate.
-
@SimonSchroeder said in Conditional operator as a statement:
The general rule is to never user ?:, but to use regular if/else instead.
Hi Simon. I always read your posts with interest. To be 100% clear, you are not speaking about using
? :
in general in its normal "expression-result" context are you? You have no problem with e.g.variable = b ? x() : y();
, do you? Only with using it as a statement,b ? x() : y();
, right? Where we are indeed all agreeing this is not a "recommended" construct.Reading through the C++ standard now I come across two apparently legitimate uses of
? :
which are surprising to me at least, and germane to this thread.First, they spend time discussing what to do when either side of the
:
is of typevoid
. Which I cannot see as usable in any context where the expression result is used (e.g. assignment to variable or in anif
condition). This only makes sense (to me) in statementcond ? voidFunc() : voidFunc2();
Second, they further comment on the result of the
:
being potentially an lvalue rather than the typical rvalue one would expect. This only makes sense (to me) in statement(x ? y : z) = 42;
which perhaps surprisingly is apparently legitimate.
@JonB said in Conditional operator as a statement:
(x ? y : z) = 42;
Should remember this next time I ask for code review for a C++ commit :-D
-
@JonB said in Conditional operator as a statement:
(x ? y : z) = 42;
Should remember this next time I ask for code review for a C++ commit :-D
@jsulm
Indeed :) I took this from https://en.cppreference.com/w/cpp/language/operator_other.html, at the end of the Conditional operator sub-topic, where they give:// simple lvalue example int m = 10; (n == m ? n : m) = 7; // n == m is false, so m = 7
! :)
-
@SimonSchroeder said in Conditional operator as a statement:
The general rule is to never user ?:, but to use regular if/else instead.
Hi Simon. I always read your posts with interest. To be 100% clear, you are not speaking about using
? :
in general in its normal "expression-result" context are you? You have no problem with e.g.variable = b ? x() : y();
, do you? Only with using it as a statement,b ? x() : y();
, right? Where we are indeed all agreeing this is not a "recommended" construct.Reading through the C++ standard now I come across two apparently legitimate uses of
? :
which are surprising to me at least, and germane to this thread.First, they spend time discussing what to do when either side of the
:
is of typevoid
. Which I cannot see as usable in any context where the expression result is used (e.g. assignment to variable or in anif
condition). This only makes sense (to me) in statementcond ? voidFunc() : voidFunc2();
Second, they further comment on the result of the
:
being potentially an lvalue rather than the typical rvalue one would expect. This only makes sense (to me) in statement(x ? y : z) = 42;
which perhaps surprisingly is apparently legitimate.
@JonB said in Conditional operator as a statement:
Second, they further comment on the result of the
:
being potentially an lvalue rather than the typical rvalue one would expect. This only makes sense (to me) in statement(x ? y : z) = 42;
which perhaps surprisingly is apparently legitimate.
++++++++++[>++++++++++<-]>+++++. T >++++++++++[>++++++++++<-]>+++++++++++++++++. h +++++++++. a +++++. n --------. k +++. s +++++++++++++. , >++++++++++[>++++++++++<-]>++++++++++++. (space) <++++[>++++++++<-]>. I >++++++++++[>++++++++++<-]>+. (space) +++++++++++++++. h +. a +++. t ---------. e >++++++++++[>++++++++++<-]>+. (space) +++++++++++++++. i ----. t +. .
-
@JonB said in Conditional operator as a statement:
Second, they further comment on the result of the
:
being potentially an lvalue rather than the typical rvalue one would expect. This only makes sense (to me) in statement(x ? y : z) = 42;
which perhaps surprisingly is apparently legitimate.
++++++++++[>++++++++++<-]>+++++. T >++++++++++[>++++++++++<-]>+++++++++++++++++. h +++++++++. a +++++. n --------. k +++. s +++++++++++++. , >++++++++++[>++++++++++<-]>++++++++++++. (space) <++++[>++++++++<-]>. I >++++++++++[>++++++++++<-]>+. (space) +++++++++++++++. h +. a +++. t ---------. e >++++++++++[>++++++++++<-]>+. (space) +++++++++++++++. i ----. t +. .
-
@J.Hilk
I recognise the code language in your blob! It is "brainf*ck", and I have previously done a bit of coding/playing in it! :) One of the finest, simple languages out there, I don't know why it is not used widely in real world programming ;-)