Как вы расставляете скобки, что вы включаете в блоки, как вы записываете логические выражения?.. Задумываетесь ли вы о том, что следуя простым правилам, вы можете не только сделать код более читабельным, но и облегчить отладку, улучшить диагностику, повысить производительность?..
Предлагаю 5К мыслей и ссылки на style guide-ы (далее SG). Надеюсь, что эта статья станет приятным и лёгким чтивом. И я уверен, что она затрагивает далеко не все вопросы и надеюсь на содержательное обсуждение.
Строго говоря, подобные вещи можно написать не только про if. Именно if выбран почти случайно (в конце концов, а почему бы и нет?). Идею этой статьи подкинул f0b0s. Её (идею) поддержали сразу несколько человек, я тоже начал ждать статью; но так и не дождавшись, решил сам поднять это знамя. f0b0s, спасибо за идею, извиняюсь, если опередил, жду комментариев.
Для полноты уделим секунду банальным вещам.
Идеальный вариант писать фигурные скобки везде, а каждое выражение if/else/else_if
причём некоторые SGы рекомендуют писать else на новой строке
Тогда else получается с таким же отступом, что и соответствующий if. Но в этом вопросе нет единства.
Если вы всё же опускаете скобки (в чём нет никакого криминала), то надо учитывать два аспекта. Во-первых, придерживаться одинаковой тактики для блоков if и else:
И, во-вторых, не записывать весь if в одну строку
Смешение стилей в пределах одного if/else затрудняет его чтение, а размещение нескольких выражений в одной строке ещё и затрудняет отладку; в последнем примере cond() и act() расположены в одной строке; это затрудняет поиск ошибок по номером срок и отладку.
Используйте преимущества С++. Если переменная нужна только в блоке, то и создавайте её только в блоке.
Это сбережёт процессорное время, память… в общем всё, что так дорого каждому человеку, исповедующему гуманистические идеалы :-)
В выражениях if/else сперва описывайте нормальный ход событий, а в блок else выносите обработку нештатных ситуаций. Это упрощает чтение программы:
Прежде всего, в C++ не стоит следовать стилю C писать
Стандарт С++ не гарантирует, что float(0) и даже int(0) реализуются как «все биты 0» (хотя, конечно, это работает, но это чисто случайно :-)).
Если вам нужно проверить на равенство 0, то лучше написать именно это:
В качестве условия следует использовать только логические величины. Это же, кстати относится и к циклам:
Если логическое выражение состоит из нескольких частей, то самой плохой практикой является запись их всех в кучу. Можно ли быстро понять, что тут написано?
Подсветка, конечно, помогла бы, но и без подсветки следующее выражение читается на много проще:
Но совсем идеально, ввести в программу дополнительные переменные
Такую программу на много проще читать, и кроме того, переменные isInside и isGreen могут пригодиться в дальнейшем.
А для пущей читабельности, можно поставить скобки вокруг логических выражений в первых двух строчках.
Выражения лучше выносить из условий
Это делает код на много читабельный, чем
Кроме того, это перекликается с общей идеей по-возможности разгружать логическое выражение, которая уже была высказана выше.
Ну и, конечно, «каждому выражению своя строка!».
Опять же, сложно читать, сложно отлаживать, сложно локализовать ошибки.
По уже изложенным причинам, в логических выражениях лучше не выполнять присвоения:
Это приводит ко множеству бед. Ра��растание логического выражения, размещение множества вызовов в одной строке. Появлению рядом двух похожих (внешне) операторов "=" и "==", что дополнительно затрудняет чтение и увеличивает вероятность ошибок и опечаток.
Очень частой ошибкой, является написание одного "=", вместо двух ("=="). Чтобы компилятор сразу же дёрнул вас за руку, некоторые люди вырабатывают привычку писать сравнения наоборот (признаюсь, я не смог её выработать в себе :-))
Если писать не
а
то вы можете не бояться опечатать и написать "=" вместо "==". В хорошем варианте программа просто не скомпилится, если вы допустите такую опечатку.
Если что-то забыл, спасибо за комментарии :-)
Пара хороших SG:
Классический SG. Обратите внимание на ссылки внизу — там есть ещё более обширные документы.
SG от Google. Стоит изучить, так как она не во всём солидарна с вышеупомянутой SG.
upd Спасибо всем прокомментировавшим! Обсуждение (как я и ожидал) получилось интересней статьи :-) Я не вношу замечания в статью по двум причинам. Многие замечания (равносправедливые) противоречат друг другу (что не удивительно, при обсуждении подобных тем). И второе, если я внесу все правки, то обсуждение станет совершенно непонятным и статья утратит свою лучшую часть :-) Пусть уж всё остаётся как есть и «ошибки»(?) допущенные в статье станут иллюстрацией к обсуждению.
Предлагаю 5К мыслей и ссылки на style guide-ы (далее SG). Надеюсь, что эта статья станет приятным и лёгким чтивом. И я уверен, что она затрагивает далеко не все вопросы и надеюсь на содержательное обсуждение.
Строго говоря, подобные вещи можно написать не только про if. Именно if выбран почти случайно (в конце концов, а почему бы и нет?). Идею этой статьи подкинул f0b0s. Её (идею) поддержали сразу несколько человек, я тоже начал ждать статью; но так и не дождавшись, решил сам поднять это знамя. f0b0s, спасибо за идею, извиняюсь, если опередил, жду комментариев.
Для полноты уделим секунду банальным вещам.
Фигурные скобки
Идеальный вариант писать фигурные скобки везде, а каждое выражение if/else/else_if
// ХОРОШО
if (a == b) {
foo();
} else {
bar();
}причём некоторые SGы рекомендуют писать else на новой строке
// Не
} else {
// а
}
else {
// или
}
else
{Тогда else получается с таким же отступом, что и соответствующий if. Но в этом вопросе нет единства.
Если вы всё же опускаете скобки (в чём нет никакого криминала), то надо учитывать два аспекта. Во-первых, придерживаться одинаковой тактики для блоков if и else:
// ПОХУЖЕ
if (a == b) {
foo();
bar();
} else
bazzz();И, во-вторых, не записывать весь if в одну строку
// СОВСЕМ ПЛОХО if (cond()) act(); else err();
Смешение стилей в пределах одного if/else затрудняет его чтение, а размещение нескольких выражений в одной строке ещё и затрудняет отладку; в последнем примере cond() и act() расположены в одной строке; это затрудняет поиск ошибок по номером срок и отладку.
И ещё два замечания о блоках
Создавайте переменные только при необходимости
Используйте преимущества С++. Если переменная нужна только в блоке, то и создавайте её только в блоке.
// ПЛОХО
SomeClass p; // нужен только в блоке
if (x == y) {
p.moveTo(x, y);
p.logResultsOfMovement();
}// ХОРОШО
if (x == y) {
SomeClass p; // нужен только в блоке
p.moveTo(x, y);
p.logResultsOfMovement();
}Это сбережёт процессорное время, память… в общем всё, что так дорого каждому человеку, исповедующему гуманистические идеалы :-)
Описывайте сперва нормальный ход событий
В выражениях if/else сперва описывайте нормальный ход событий, а в блок else выносите обработку нештатных ситуаций. Это упрощает чтение программы:
// ХОРОШО
bool errorFlag = openConnection();
if (!errorFlag) {
doJob();
} else {
dropJob();
}Логические выражения
C++ не С
Прежде всего, в C++ не стоит следовать стилю C писать
// ПЛОХО
if (float_num) {}
if (int_num) {}Стандарт С++ не гарантирует, что float(0) и даже int(0) реализуются как «все биты 0» (хотя, конечно, это работает, но это чисто случайно :-)).
Если вам нужно проверить на равенство 0, то лучше написать именно это:
// ХОРОШО
if (float_num != .0) {}
if (int_num != 0) {}В качестве условия следует использовать только логические величины. Это же, кстати относится и к циклам:
// ХОРОШО
while (true) {}
// ПЛОХО
while (1) {}
for (;;) {}Разделяйте логические выражения на части
Если логическое выражение состоит из нескольких частей, то самой плохой практикой является запись их всех в кучу. Можно ли быстро понять, что тут написано?
// ПЛОХО if (figureX > leftLimit && figureX < fightLimit && figureColor == GREEN)
Подсветка, конечно, помогла бы, но и без подсветки следующее выражение читается на много проще:
// ХОРОШО
if (figureX > leftLimit &&
figureX < fightLimit &&
figureColor == GREEN)Но совсем идеально, ввести в программу дополнительные переменные
// ОЧЕНЬ МИЛО bool isInside = figureX > leftLimit && figureX < fightLimit; bool isGreen = figureColor == GREEN; if (isInside && isGreen)
Такую программу на много проще читать, и кроме того, переменные isInside и isGreen могут пригодиться в дальнейшем.
А для пущей читабельности, можно поставить скобки вокруг логических выражений в первых двух строчках.
Выражения в условиях
Выражения лучше выносить из условий
// ХОРОШО
bool dataReaded = readDdata(fileName);
if (dataReaded) {}Это делает код на много читабельный, чем
// ПЛОХО
if (readDdata(fileName)) {}Кроме того, это перекликается с общей идеей по-возможности разгружать логическое выражение, которая уже была высказана выше.
Ну и, конечно, «каждому выражению своя строка!».
// СОВСЕМ ПЛОХО
if (readDdata(getFileNameFromArray(getEnvAsArray()))) {}Опять же, сложно читать, сложно отлаживать, сложно локализовать ошибки.
Присвоения в условиях
По уже изложенным причинам, в логических выражениях лучше не выполнять присвоения:
// ПЛОХО if (lid = getLabel() == curentLabel())
Это приводит ко множеству бед. Ра��растание логического выражения, размещение множества вызовов в одной строке. Появлению рядом двух похожих (внешне) операторов "=" и "==", что дополнительно затрудняет чтение и увеличивает вероятность ошибок и опечаток.
Очень частой ошибкой, является написание одного "=", вместо двух ("=="). Чтобы компилятор сразу же дёрнул вас за руку, некоторые люди вырабатывают привычку писать сравнения наоборот (признаюсь, я не смог её выработать в себе :-))
Если писать не
// ПЛОХО? if (x == 1)
а
// ХОРОШО? if (1 == x)
то вы можете не бояться опечатать и написать "=" вместо "==". В хорошем варианте программа просто не скомпилится, если вы допустите такую опечатку.
Кажется ничего не забыл
Если что-то забыл, спасибо за комментарии :-)
Пара хороших SG:
Классический SG. Обратите внимание на ссылки внизу — там есть ещё более обширные документы.
SG от Google. Стоит изучить, так как она не во всём солидарна с вышеупомянутой SG.
upd Спасибо всем прокомментировавшим! Обсуждение (как я и ожидал) получилось интересней статьи :-) Я не вношу замечания в статью по двум причинам. Многие замечания (равносправедливые) противоречат друг другу (что не удивительно, при обсуждении подобных тем). И второе, если я внесу все правки, то обсуждение станет совершенно непонятным и статья утратит свою лучшую часть :-) Пусть уж всё остаётся как есть и «ошибки»(?) допущенные в статье станут иллюстрацией к обсуждению.
