Oh, I just found how to do it in g++: -Wno-parentheseshgm wrote:The pedantic compiler warning about this can be turned off.
Thanks!
Moderators: hgm, Rebel, chrisw
Oh, I just found how to do it in g++: -Wno-parentheseshgm wrote:The pedantic compiler warning about this can be turned off.
Maybe you noticed I was specifically talking about && versus ||.hgm wrote:A more realistic example could besyzygy wrote:Ok, so you findmore readable thanCode: Select all
if (a < b || c > 5 && d == 2)
Very well. I certainly don't.Code: Select all
if (a < b || (c > 5 && d ==2))
versusCode: Select all
if(4*x + 1 < 2*y || f(3*x - 1) > 5 && d[i - 1] == 2))
Good layout is enormously more helpful to code readability than parentheses.Code: Select all
if((((4*x) + 1) < (2*y)) || ((f((3*x) - 1) > 5) && (d[i - 1] == 2))))
I am glad you have found practical information to exploit in this thread.AlvaroBegue wrote:Oh, I just found how to do it in g++: -Wno-parentheseshgm wrote:The pedantic compiler warning about this can be turned off.
Thanks!
Sure. But expresions with && and || can occur in multiple levels too (e.g. A || B && (C || D && E)), and it often happens that you really need parenthesis in the operands of those (e.g. because they are function calls, or things like "(x & MASK) == 0"), and adding unneeded parentheses at the level of && and || would really obfuscate things.syzygy wrote:Maybe you noticed I was specifically talking about && versus ||.
My take on this argument.hgm wrote:OTOH, long, informative names make the line much longer, forcing it to be split over several lines, and pushing closing parentheses out of view.
The keyword in my remark was excessive. In Ronald's example there was only a single pair of parentheses, and that of course is always trivial, because it is obvious which closing parenthesis belongs to which opening parenthesis if there is only one. But it becomes tricky when they are nested, and several of them follow each other, so that you now really have to count them to realize which belongs with which. Consecutive parentheses are best avoided, and attempts to do so lead to bugs when one is ignorant on operator priorities.
The pedantic compiler warning about this can be turned off.
(In 1988 I programmed in a dialect of LISP for three years. Problem was that it didn't have good type checking for you only have lists, atoms and dotted pairs. Therefor you get a lot of run time errors instead of compile time errors. For instance if you put the arguments in the wrong order. In the mean time they were fixing the garbage collector bugs for they created a LISP dialect on top of C. Nowadays I still use lists instead of arrays.)bob wrote:My take on this argument.hgm wrote:OTOH, long, informative names make the line much longer, forcing it to be split over several lines, and pushing closing parentheses out of view.
The keyword in my remark was excessive. In Ronald's example there was only a single pair of parentheses, and that of course is always trivial, because it is obvious which closing parenthesis belongs to which opening parenthesis if there is only one. But it becomes tricky when they are nested, and several of them follow each other, so that you now really have to count them to realize which belongs with which. Consecutive parentheses are best avoided, and attempts to do so lead to bugs when one is ignorant on operator priorities.
The pedantic compiler warning about this can be turned off.
#1, && has higher precedence than ||. I would not resort to parens until I had a complex expression with multiple &&'s and ||'s, which could become difficult to read. In general, I consider parens as something that makes code harder to read in most cases, but which can make it clearer in others. Ever heard the serenity prayer alcoholics and such are taught over and over? Paraphrased:
"God, grant me the serenity to avoid using parentheses when they are not needed, the courage to use them when they are needed, and the wisdom to know the difference."
Fits for me.
#2. I don't particularly like parentheses. I've had to (been forced to) work with Lisp several times in the past. I consider that a "write-only programming language." It is very difficult to read something where adding an "extra" level of parens is not benign, but actually affects the final results of the expression.
A quick look at crafty gives the strong impression that in practice you do use (redundant) parentheses whenever you mix && and || in one conditional expression.bob wrote:I would not resort to parens until I had a complex expression with multiple &&'s and ||'s, which could become difficult to read. In general, I consider parens as something that makes code harder to read in most cases, but which can make it clearer in others.
Code: Select all
search.c:
if (smp_idle && moves_searched > 1 &&
tree->nodes_searched - start_nodes > smp_split_nodes && (ply > 1 ||
(smp_split_at_root && NextRootMoveParallel()))) {
if (tree->nodes_searched > noise_level || (tree->parent &&
tree->parent->nodes_searched > noise_level)) {
utility.c (this one occurs 3 times):
if (((tmove[0] >= 'a' && tmove[0] <= 'z') || (tmove[0] >= 'A' &&
tmove[0] <= 'Z')) || !strcmp(tmove, "0-0")
|| !strcmp(tmove, "0-0-0")) {
setboard.c:
if (((Castle(0, white) & 2) && (PcOnSq(A1) != rook))
|| ((Castle(0, white) & 1) && (PcOnSq(H1) != rook))
|| ((Castle(0, black) & 2) && (PcOnSq(A8) != -rook))
|| ((Castle(0, black) & 1) && (PcOnSq(H8) != -rook))) {
if ((twtm && EnPassant(0) && (PcOnSq(EnPassant(0) + 8) != -pawn)
&& (PcOnSq(EnPassant(0) - 7) != pawn)
&& (PcOnSq(EnPassant(0) - 9) != pawn)) || (Flip(twtm)
&& EnPassant(0)
&& (PcOnSq(EnPassant(0) - 8) != pawn)
&& (PcOnSq(EnPassant(0) + 7) != -pawn)
&& (PcOnSq(EnPassant(0) + 9) != -pawn))) {
evaluate.c:
tree->dangerous[white] = (Queens(white) && TotalPieces(white, occupied) > 9)
|| (TotalPieces(white, rook) > 1 && TotalPieces(white, occupied) > 15);
tree->dangerous[black] = (Queens(black) && TotalPieces(black, occupied) > 9)
|| (TotalPieces(black, rook) > 1 && TotalPieces(black, occupied) > 15);
if ((TotalPieces(white, occupied) == 0 &&
tree->pawn_score.passed[black])
|| (TotalPieces(black, occupied) == 0 &&
tree->pawn_score.passed[white]))
if (TotalPieces(white, occupied) == 3 &&
TotalPieces(black, occupied) == 3 &&
((TotalPieces(white, pawn) < 4 && TotalPieces(black, pawn) < 4)
|| Abs(TotalPieces(white, pawn) - TotalPieces(black,
pawn)) < 2))
if (Rank(square) == ((side) ? RANK6 : RANK3)
&& SetMask(square + direction[side]) & Pawns(enemy)
&& ((File(square) < FILEH &&
SetMask(square + 9 - 16 * side) & Pawns(side)
&& !(mask_hidden_right[side][File(square)] & Pawns(enemy)))
|| (File(square) > FILEA &&
SetMask(square + 7 - 16 * side) & Pawns(side)
&& !(mask_hidden_left[side][File(square)] & Pawns(enemy))))) {
if (TotalPieces(side, pawn) == 1 && TotalPieces(enemy, pawn) == 0 &&
((TotalPieces(side, occupied) == 5 && TotalPieces(enemy, occupied) == 5)
|| ((TotalPieces(side, occupied) == 9 &&
TotalPieces(enemy, occupied) == 9)))) {
book.c:
if (bs_percent[i] < bs_percent[i + 1]
|| (bs_percent[i] == bs_percent[i + 1]
&& bs_value[i] < bs_value[i + 1])) {
if ((book_status[i] & book_accept_mask &&
!(book_status[i] & book_reject_mask))
|| (!(book_status[i] & book_reject_mask) && (bs_percent[i]
|| book_status[i] & 0x18 || (wtm && book_status[i] & 0x80)
|| (!wtm && book_status[i] & 0x20))))
if ((book_status[i] & book_accept_mask &&
!(book_status[i] & book_reject_mask))
|| (!(book_status[i] & book_reject_mask) && ((wtm &&
book_status[i] & 0x80) || (!wtm &&
book_status[i] & 0x20))))
if (!puzzling && (!book_random || (mode == tournament_mode &&
np < book_search_trigger))) {
drawn.c:
if ((TotalPieces(white, occupied) == 6 && !Bishops(white) && Material > 0)
|| (TotalPieces(black, occupied) == 6 && !Bishops(black)
&& Material < 0))
Code: Select all
if (!Attacks(tree, to, enemy)
&& (directions[from][to] != check_direction1)
&& (directions[from][to] != check_direction2))
I only do them to suppress warnings. Not because I like the style. I've tried for years to keep warnings out. I've pretty well succeeded, although it seems new warnings come with each new compiler release.syzygy wrote:A quick look at crafty gives the strong impression that in practice you do use (redundant) parentheses whenever you mix && and || in one conditional expression.bob wrote:I would not resort to parens until I had a complex expression with multiple &&'s and ||'s, which could become difficult to read. In general, I consider parens as something that makes code harder to read in most cases, but which can make it clearer in others.For some of these probably even HGM will agree parentheses improve readability, but most expressions are quite simple.Code: Select all
search.c: if (smp_idle && moves_searched > 1 && tree->nodes_searched - start_nodes > smp_split_nodes && (ply > 1 || (smp_split_at_root && NextRootMoveParallel()))) { if (tree->nodes_searched > noise_level || (tree->parent && tree->parent->nodes_searched > noise_level)) { utility.c (this one occurs 3 times): if (((tmove[0] >= 'a' && tmove[0] <= 'z') || (tmove[0] >= 'A' && tmove[0] <= 'Z')) || !strcmp(tmove, "0-0") || !strcmp(tmove, "0-0-0")) { setboard.c: if (((Castle(0, white) & 2) && (PcOnSq(A1) != rook)) || ((Castle(0, white) & 1) && (PcOnSq(H1) != rook)) || ((Castle(0, black) & 2) && (PcOnSq(A8) != -rook)) || ((Castle(0, black) & 1) && (PcOnSq(H8) != -rook))) { if ((twtm && EnPassant(0) && (PcOnSq(EnPassant(0) + 8) != -pawn) && (PcOnSq(EnPassant(0) - 7) != pawn) && (PcOnSq(EnPassant(0) - 9) != pawn)) || (Flip(twtm) && EnPassant(0) && (PcOnSq(EnPassant(0) - 8) != pawn) && (PcOnSq(EnPassant(0) + 7) != -pawn) && (PcOnSq(EnPassant(0) + 9) != -pawn))) { evaluate.c: tree->dangerous[white] = (Queens(white) && TotalPieces(white, occupied) > 9) || (TotalPieces(white, rook) > 1 && TotalPieces(white, occupied) > 15); tree->dangerous[black] = (Queens(black) && TotalPieces(black, occupied) > 9) || (TotalPieces(black, rook) > 1 && TotalPieces(black, occupied) > 15); if ((TotalPieces(white, occupied) == 0 && tree->pawn_score.passed[black]) || (TotalPieces(black, occupied) == 0 && tree->pawn_score.passed[white])) if (TotalPieces(white, occupied) == 3 && TotalPieces(black, occupied) == 3 && ((TotalPieces(white, pawn) < 4 && TotalPieces(black, pawn) < 4) || Abs(TotalPieces(white, pawn) - TotalPieces(black, pawn)) < 2)) if (Rank(square) == ((side) ? RANK6 : RANK3) && SetMask(square + direction[side]) & Pawns(enemy) && ((File(square) < FILEH && SetMask(square + 9 - 16 * side) & Pawns(side) && !(mask_hidden_right[side][File(square)] & Pawns(enemy))) || (File(square) > FILEA && SetMask(square + 7 - 16 * side) & Pawns(side) && !(mask_hidden_left[side][File(square)] & Pawns(enemy))))) { if (TotalPieces(side, pawn) == 1 && TotalPieces(enemy, pawn) == 0 && ((TotalPieces(side, occupied) == 5 && TotalPieces(enemy, occupied) == 5) || ((TotalPieces(side, occupied) == 9 && TotalPieces(enemy, occupied) == 9)))) { book.c: if (bs_percent[i] < bs_percent[i + 1] || (bs_percent[i] == bs_percent[i + 1] && bs_value[i] < bs_value[i + 1])) { if ((book_status[i] & book_accept_mask && !(book_status[i] & book_reject_mask)) || (!(book_status[i] & book_reject_mask) && (bs_percent[i] || book_status[i] & 0x18 || (wtm && book_status[i] & 0x80) || (!wtm && book_status[i] & 0x20)))) if ((book_status[i] & book_accept_mask && !(book_status[i] & book_reject_mask)) || (!(book_status[i] & book_reject_mask) && ((wtm && book_status[i] & 0x80) || (!wtm && book_status[i] & 0x20)))) if (!puzzling && (!book_random || (mode == tournament_mode && np < book_search_trigger))) { drawn.c: if ((TotalPieces(white, occupied) == 6 && !Bishops(white) && Material > 0) || (TotalPieces(black, occupied) == 6 && !Bishops(black) && Material < 0))
I did not find any example in crafty of "A || B && C" without parentheses. It would surprise me if they exist.
Another example of redundant parentheses in movgen.c:I have no problem at all with these parentheses. None of them make your code any less readable for me.Code: Select all
if (!Attacks(tree, to, enemy) && (directions[from][to] != check_direction1) && (directions[from][to] != check_direction2))
I think if you mix a lot, parens are probably ok. If you JUST mix && and ||, you should be able to write that without parens in most (but not all) cases. But along that line, what about +, -, *, /?. I ALSO don't have any problems remembering the precedence for those. Ditto if you add <,>, etc in with the arithmetic operators...Michel wrote:Here is a little C test. What is the order of precedence for ^,&,| ?
Should one still refrain from using parentheses when using these operators?