Comments 54
ИМХО, само условие как таковое, не должно зависеть от восприятия. Оно должно быть однозначным для любого читателя. Главное это разделение скобками условий на группы. Что-то на подобии как большая буква идет в начале предложения и точка в конце. Так и скобки должны отделять начало и конец некоторого условия. Тогда все неоднозначности уходят сами собой.
Кем? Компилятором или теми, кто работает с вами в команде/потом будет поддерживать код?
Пишу всегда со скобками. На всякий случай. Как-то так спокойнее. :)
Недавно на хабре была статья, в которой говорилось, что написание лишнего кода «на всякий случай» — признак плохого программиста. Я не говорю что вы плохой программист, статья такая.
Сперва проголосовал за первый вариант, потом понял, что напишу так:
if ((a != b || c != d) && !e) { }
Но ведь это, кажется, изменит смысл условия?
Аналогично. Скобки расставляю так, чтобы был понятен смысл разделения условий на группы.
Вот кстати наглядный пример к моему комментарию ниже, ваше выражение не эквивалентно описанным, потому что приоритет && больше чем || и без скобок оно выполнится не так.
Тогда уж если сохранять приоритет операций, то
if ((a != b) || ((c != d) && !e) { }
У вас перед блоком 1 скобки не хватает закрывающей.
Вы поставили четыре открывающие скобки, но только три закрывающие. Это вызовет сообщение об ошибке.
Он показал саму суть: раз уж добавлять лишние скобки, то до конца — ведь в 1м примере голосовалки все равно может быть неоднозначное восприятие. Многим приходится программировать на разных языках и там приоритет операций может быть иным, так что перестраховщики будут ставить скобку после каждой операции
Ваш первый вариант добавляет избыточности, но не делает условие понятным,
потому что с приоритетами по группам легко, все помнят, что приоритет
сравнений больше чем у логических операторов.
Я пишу так:
Несмотря на то, что порядок приоритета логических операторов мне хорошо известен, это делает код читабельнее. Особенно в таком случае, когда операция с более высоким приоритетом стоит правее.
потому что с приоритетами по группам легко, все помнят, что приоритет
сравнений больше чем у логических операторов.
Я пишу так:
if (a != b || (c != d && !e)) { }
Несмотря на то, что порядок приоритета логических операторов мне хорошо известен, это делает код читабельнее. Особенно в таком случае, когда операция с более высоким приоритетом стоит правее.
Всегда без скобок из-за того что затрудняют понимание. Если же условие обретает форму, когда больше чем 2 под-условия, то разбиваю условие на несколько bool-евых флагов, которые читать проще.
пример разбития на несколько под условий:
пример разбития на несколько под условий:
bool fileOpen = (bla-bla-bla);
bool rc4used = (bla-bla-bla);
if ( fileOpen && rc4used )
{
// code
}
Я в таких случаях ещё добавляю const к объявлению.
Я пользуюсь еще интересным приемом (правда это немножко иной язык программирования: perl):
{
a == b or last;
d > x + 150 or last;
f < 16 or last;
# все условия выполнены, выполняем действие
…
}
{
a == b or last;
d > x + 150 or last;
f < 16 or last;
# все условия выполнены, выполняем действие
…
}
Сильно смахивает на аналог конструкции:
Поэтому у меня возникают сомнения касательно правильности такого подхода
{
if (!...)
goto end;
if (!...)
goto end;
if (!...)
goto end;
// code here
end:;
}
Поэтому у меня возникают сомнения касательно правильности такого подхода
return тоже «смахивает» на goto, но его никто в этом не упрекает. Есть четкий блок, внутри него условия, несовпадение условий — выход из блока. Если внимательно присмотритесь, то выход из блока используется сплошь и рядом: досрочное завершение подпрограммы с return, досрочный выход из цикла, case, иксепшины и т.д. Это нормальный прием. Сейчас объясню почему. Обычно, логика выполнения идет по одному пути: проверка, не выполнилась — свалили, проверка, не выполнилась — свалили, и т.д. Так происходит очень часто.
Например, банальная ситуация: проверили существование отправителя, нет — ошибка и конец, проверили достаточность денег на счету, нет — ошибка и коней, с получаетелем тоже самое и в конце запись в таблицу логов, нет — ошибка и конец. Если вы будете делать это через if, то создадите многоэтажную конструкцию, на 4й ступеньке ваш код перейдет в стадию «отвратный». Я практически никогда не допускаю больше 3х вложенностей.
Если же представить выполнение задачи по моему методу, то будет примерно следующее:
ok = 0;
{
проверка1 or last;
вычисления;
проверка2 or last;
вычисления;
проверка3 or last;
вычисления;
проверка4 or last;
ok = 1;
}
ok or rollback;
В такой конструкции явно прослеживается корректная цепочка операций, а все что не удовлетворяет ей — отсекается. Попробуйте, так очень удобно и понятно
Например, банальная ситуация: проверили существование отправителя, нет — ошибка и конец, проверили достаточность денег на счету, нет — ошибка и коней, с получаетелем тоже самое и в конце запись в таблицу логов, нет — ошибка и конец. Если вы будете делать это через if, то создадите многоэтажную конструкцию, на 4й ступеньке ваш код перейдет в стадию «отвратный». Я практически никогда не допускаю больше 3х вложенностей.
Если же представить выполнение задачи по моему методу, то будет примерно следующее:
ok = 0;
{
проверка1 or last;
вычисления;
проверка2 or last;
вычисления;
проверка3 or last;
вычисления;
проверка4 or last;
ok = 1;
}
ok or rollback;
В такой конструкции явно прослеживается корректная цепочка операций, а все что не удовлетворяет ей — отсекается. Попробуйте, так очень удобно и понятно
Ну и в добавок хочу отметить, что также в коде использую еще одну практику:
Если текст условия больше чем 25 символов, то нужно либо посмотреть в название переменных, либо составить несколько bool переменных.
Ранее у программеров была эмпирическая оценка — не больше 86 символов на строку.
Пример:
1) sizeof(«boost::filesystem::file_size(fpath) < minPackedImageSize && dosHeader.e_lfanew<= boost::filesystem::file_size») больше 25 символов
2) sizeof(«boost::filesystem::file_size(fpath) < minPackedImageSize») больше чем 25!!!
3) sizeof(«dosHeader.e_lfanew <= boost::filesystem::file_size») больше чем 25
Этот доп. признак позволяет мне обратить внимание на плохо написанное условие с точки зрения эстетики, а следовательно и читабельности кода.
Разбиваю на:
т.е. благодаря этому признаку, я смог остановить на «паузу» свой мозг и посмотреть на этот «дурно пахнущий» кусок кода. В спешке я бы не заметил этого.
Если текст условия больше чем 25 символов, то нужно либо посмотреть в название переменных, либо составить несколько bool переменных.
Ранее у программеров была эмпирическая оценка — не больше 86 символов на строку.
Пример:
if(boost::filesystem::file_size(fpath) < minPackedImageSize && dosHeader.e_lfanew<= boost::filesystem::file_size)
{
// code
}
1) sizeof(«boost::filesystem::file_size(fpath) < minPackedImageSize && dosHeader.e_lfanew<= boost::filesystem::file_size») больше 25 символов
2) sizeof(«boost::filesystem::file_size(fpath) < minPackedImageSize») больше чем 25!!!
3) sizeof(«dosHeader.e_lfanew <= boost::filesystem::file_size») больше чем 25
Этот доп. признак позволяет мне обратить внимание на плохо написанное условие с точки зрения эстетики, а следовательно и читабельности кода.
Разбиваю на:
int fileSize = (int)boost::filesystem::file_size(fpath);
bool isCorrectElfanew = dosHeader.e_lfanew <= fileSize;
bool isImageLarge = fileSize > minPackedImageSize;
if( !isImageLarge && isCorrectElfanew )
{
// code
}
т.е. благодаря этому признаку, я смог остановить на «паузу» свой мозг и посмотреть на этот «дурно пахнущий» кусок кода. В спешке я бы не заметил этого.
Всегда пишу со скобками. Что-бы потом не удивляться как копилятор или интерпретатор обрабатывает приоритеты операторов.
Вот так: if(a && (b || (c && d)))
Лучше выделить в функцию, имя которой будет полностью оправдывать ее назначение.
Для 2-3 переменных — это лишнее, а для 4+ потом можно запутаться в порядке параметров.
Я бы долго бил за такое:
if (checkSomething(a, b, c, d, e)) { doSomething(); }
Учитывая, что даже человеческие названия переменных одинакового типа будут читаться не лучше «a, b, c, d, e».
Я бы долго бил за такое:
if (checkSomething(a, b, c, d, e)) { doSomething(); }
Учитывая, что даже человеческие названия переменных одинакового типа будут читаться не лучше «a, b, c, d, e».
if (checkSmth1(a,b) || (checkSmth2(c,d) && checkSmth3(e))) {}
:)
Согласен с автором, что сложное условие лучше выносить в функцию (функции). При этом одна функция не обязательно должна содержать одно условие. Например:
Возможно, для данного примера делать отдельные функции избыточно и скобок вполне хватит для улучшения восприятия кода.
if (IsSmth1(a,b) || IsSmth2(c,d,e)) {}
...
bool IsSmth1(a, b) { return a != b; }
...
bool IsSmth2(c, b, e) { return c != d && !e; }
Возможно, для данного примера делать отдельные функции избыточно и скобок вполне хватит для улучшения восприятия кода.
Код есть искусство. Он должен читаться легко и быстро. Логическое выражение с лишними скобками лишь вынесет мозг в попытке его прочитать, что замедлит работу. А без лишних скобок логика условия сразу будет понятной.
Обычно пишу со скобками, когда выражения визуально сложны для восприятия. Выражения со >> и << всегда заключаю в скобки, т.к. уже напарывался на неверную запись условия. На мой взгляд, в C и C++ перемудрили с приоритетами.
Приоритетам логических операций не очень доверяю, поэтому так:
if (a != b || (c != d && !e)) { }
Сравнения ставлю в скобки только в конструкциях вида
bool q=(a!=b);
или
bool x=(a<0? a<b: a>b);
if (a != b || (c != d && !e)) { }
Сравнения ставлю в скобки только в конструкциях вида
bool q=(a!=b);
или
bool x=(a<0? a<b: a>b);
if( (a != b || c != d) &&
!(x != y || z != w) &&
(g != f || r != w) )
{
}
может не очень в тему, но я обожаю писать конструкции типа a=(bla bla)?(bla bla):(bla bla bla);
так вот в таких случаях почти всегда очень помогают скобки
а в обычных случаях скобки редко использую, в основном только в сложных условиях
так вот в таких случаях почти всегда очень помогают скобки
а в обычных случаях скобки редко использую, в основном только в сложных условиях
Приведенный пример я бы написал так:
Т.е. скобкаи я всегда явно выделяю порядок проверки условия.
if (a != b || (c != d && !e)) { }
Т.е. скобкаи я всегда явно выделяю порядок проверки условия.
Если бы не было паскаля, то все бы гарантированно знали, что в выражении (a != b) || (c != d) скобки не нужны.
За одно то, что в паскале логические операторы имеют приоритет над сравнением, Вирт будет гореть в аду.
За одно то, что в паскале логические операторы имеют приоритет над сравнением, Вирт будет гореть в аду.
А за то, что в C операции << и & имеют приоритет ниже, чем сложение? Хотя << это умножение, а & — остаток от деления.
Не знаю, стоит ли Вирту отвечать за это.
А если серьезно, то претензия не принимается, т.к. в конструкции a != b || c != d трактовка может быть только одна. Никому в голову не придет что имелось в виду a != (b || c) != d. Поэтому именно за то что в паскале автор языка заставляет ставить скобки в совершенно однозначной ситуации надо руки обрывать.
А с битовыми операциями другое.
Там a << b + c может по замыслу программиста быть и (a << b) + c и a << (b + c) поэтому с целью увеличения читаемости там скобки не помешают.
А с битовыми операциями другое.
Там a << b + c может по замыслу программиста быть и (a << b) + c и a << (b + c) поэтому с целью увеличения читаемости там скобки не помешают.
Всегда без лишних скобок. Они чаще только запутывают и ухудшают читаемость.
А если возникает необходимость в скобках для улучшения читаемости, то стоит рассмотреть вариант с изменением порядка условий (не нарушая, разумеется, логику) и разделением на несколько строк.
А если возникает необходимость в скобках для улучшения читаемости, то стоит рассмотреть вариант с изменением порядка условий (не нарушая, разумеется, логику) и разделением на несколько строк.
Sign up to leave a comment.
Как вы пишете условия в СИ-подобных языках? Со скобками в условиях или без?