Зачем использовать! Boolean_variable Over boolean_variable == false

60

Комментарий к этому вопросу: проверка, возвращает ли метод значение false: присваивать результат временной переменной или помещать вызов метода непосредственно в условное выражение? говорит, что вы должны использовать !booleanвместо того, чтобы boolean == falseпри тестировании условий. Почему? Для меня boolean == falseэто намного более естественно на английском языке и более явно. Я извиняюсь, если это просто вопрос стиля, но мне было интересно, была ли какая-то другая причина для этого предпочтения !boolean?

оборота
источник
28
Короче написать.
Зенон
39
Это как делать boolean == true: это не имеет смысла. Выражения внутри ifоператоров - это просто выражения. Если что-то уже вычисляется в булево выражение, зачем вам добавлять проверку, чтобы заставить это оценить?
Maxpm
10
@zzzzBov: Хм нет. Это не так, как большинство программистов (в стиле C).
Амара
9
@zzzzBov: Ваш комментарий неоднозначен. Если вы имели в виду, что !boolean_variableтак делают большинство программистов на С, я согласен.
Кит Томпсон
29
И что более важно, почему никто не хочет писать boolean != true?

Ответы:

153

Когда я вижу такую ​​строку if (!lateForMeeting()), я читаю это как «Если не опаздывает на встречу» , что довольно просто понять, в отличие от того, if (lateForMeeting() == false)что я читал бы как «Если факт, что я опаздываю на встречу, является ложным " .

Они идентичны по смыслу, но первое ближе к тому, как будет строиться эквивалентное английское предложение.

кба
источник
27
+1 В Python вы действительно пишете if not late_for_meeting:)
phunehehe
42
Я утверждаю, что если «если ___ ложно» звучит более естественно, чем «если не ___», то имя ___ нуждается в улучшении.
Майк ДеСимоне
12
В Perl вы можете написатьunless late_for_meeting
Хенрик Рипа
4
@HenrikRipa: Кажется, что почти все, что вы можете напечатать, является правовым кодом в Perl. Делает ли он то, что вы хотите, это другой вопрос;)
Адам Робинсон
4
@ A-Cube У меня не было бы такого метода для начала. Вместо этого я бы вызвал метод done(). Двойные негативы плохие.
KBA
97

Написание == falseи == trueявляется излишним. Это также может привести к произвольным крайностям. Если вы начнете писать

if (condition == false) { ... }

Тогда почему бы и нет

if ((condition == false) == true) { ... }

Или почему нет

if ((someExp == anotherExp) == true) { ... }

Мораль этой истории в том, что если conditionэто логическое выражение, то вам не нужно добавлять == false; для этого и нужен оператор !;)

Андрес Ф.
источник
Не думал об этом!
Ell
51
== falseНЕ избыточен, просто более многословен, чем !. OTOH, == trueэто избыточно.
Ден04
4
@ dan04 Ты прав. Однако в том смысле, в каком я это имел в виду, это остается плохой идеей. Рассмотрим (exp1 != exp2)против ((exp1 == exp2) == false). Следует признать, что это надуманные сценарии, но, тем не менее, вы почти никогда не должны писать явные сравнения с истиной или ложью. Точно так же, как вы должны использовать оператор !=, так что вы должны использовать !.
Андрес Ф.
26
@ dan04: это избыточно, когда язык уже предлагает !.
DeadMG
5
@ dan04: всякий раз, когда вы пишете bool_expression == bool_literal, == ...это избыточно. Независимо от того, проверяете ли вы на истинность или ложь, не имеет значения Это просто изменение порядка последовательных / альтернативных блоков. Примеры Андреса прекрасно иллюстрируют этот момент. Большинство современных компиляторов оптимизируют избыточность, но она все еще избыточна.
Lèse Majesté
70

В C и некоторых похожих языках сравнение логических выражений на равенство falseили trueявляется опасной привычкой.

В C любое скалярное выражение (числовое или указательное) может использоваться в логическом контексте, например, как условие ifоператора. Правило C - это то, что if (cond)эквивалентно if (cond != 0)- т. Е. Ноль равен false, а любое ненулевое значение - true. Если condимеет тип указателя, 0обрабатывается как константа нулевого указателя; if (ptr)значит if (ptr != NULL).

Это значит, что

if (cond)

а также

if (cond == true)

не означает то же самое . Первое верно, если condненулевое; вторая верна, только если она равна true, что в C (если у вас есть #include <stdbool.h>) просто 1.

Например, isdigit()функция, объявленная в, <ctype.h>возвращает intзначение, 0если аргумент является цифрой, ненулевое, если это не так. Он может вернуться, 42чтобы указать, что условие истинно. Сравнение 42 == trueне удастся.

Бывает, что 0это единственное значение, которое считается ложным, поэтому сравнение на равенство falseбудет работать; if (!cond)и if (cond == false)сделать то же самое. Но если вы собираетесь воспользоваться этим, вы должны помнить, что сравнивать с falseэто нормально, а сравнивать true- нет. Еще хуже то, что сравнение trueбудет работать большую часть времени (например, операторы равенства и реляционные операции всегда дают либо 0или 1). Это означает, что любые ошибки, которые вы вносите с помощью этого, все еще могут быть трудно отследить. (Не волнуйтесь, они появятся, как только вы представите код важному клиенту.)

C ++ имеет немного другие правила; например, его boolтип немного более тесно интегрирован в язык и if (cond)преобразуется condв тип bool. Но эффект (в основном) тот же.

Некоторые другие языки имеют то, что можно назвать булевыми значениями с лучшим поведением, так что cond == trueи cond == false(или любой другой синтаксис) безопасен. Тем не менее, на каждом языке, который я видел, есть оператор notили !; это там, так что вы могли бы также использовать его. Использование, cond == falseа не !condили not cond, на мой взгляд, не улучшает читаемость. (Это правда, что !персонаж может быть трудно увидеть с первого взгляда; иногда я добавляю пробел после, !чтобы избежать этого.)

И часто вы можете избежать проблемы и улучшить ясность, слегка переставив код. Например, а не:

if (!cond) {
    do_this();
}
else {
    do_that();
}

Вы могли бы написать:

if (cond) {
     do_that();
}
else {
    do_this();
}

Это не всегда лучше, но не мешает искать возможности там, где это есть.

Резюме: В C и C ++ сравнения на равенство trueи falseопасны, слишком многословны и некачественны. Во многих других языках такие сравнения могут не быть опасными, но они все еще слишком многословны и некачественны.

Кит Томпсон
источник
+1 для этого, являющегося единственным ответом с фактическим полезным техническим объяснением.
Майк Накис
Я до сих пор так думаю, независимо от языка программирования, я всегда предполагаю, что == trueэто небезопасно. Так лучше.
Dervall
1
@Dervall: предполагать что-то, что просто не так, тоже не годится. В некоторых языках есть несколько угловых случаев, когда сравнение на равенство не только безопасно, но и на самом деле уместно, например, в Haskell, который имеет сильную систему типов без неявных приведений с выводом двунаправленного типа, можно написать, (==True) . fчтобы уточнить, что мы хотим -> Boolсоздать экземпляр полиморфной функции return f. Это понятнее not . not . fи менее неловко, чем (f :: a -> Bool).
оставил около
Также вполне уместно делать что-то вроде pred(x)==pred(y)функции, возвращающей bool pred. Альтернатива, с pred(x)? pred(y) : !pred(y)которой вы согласитесь, вряд ли приемлема.
оставил около
1
@leftaroundabout: Хорошо, если вы это знаете pred(x)и pred(y)используете одно и то же значение для обозначения истины, что является безопасным допущением в некоторых языках, но не в других. В C, например, вы можете написать !!pred(x) == !!pred(y).
Кит Томпсон
14

Эти два функционально идентичны, поэтому какой из них использовать - дело вкуса.

Основная причина, которую я использую, == falseзаключается в том, что я обнаружил, что !это слишком легко упускать из виду при просмотре кода.

Я был сильно укушен этим, и у меня появилась привычка ясно показывать это при проверке на ложность.


Если бы оператор был назван notкак в Паскале, я не думаю, что это стало бы проблемой.

оборота user1249
источник
5
По этой самой причине проект на C ++, над которым я работал для некоторого программного обеспечения для медицинских устройств, имел стандарт кодирования, который предписывался == falseвместо !той же самой причины (чтобы выделить его). Однако не было никаких требований к использованию == true, поэтому любое ненулевое значение по-прежнему работало как надо.
tcrosley
12
Я всегда находил этот аргумент неубедительным - в C / C ++ / C # / Java / и т. Д. Есть и другие места, где отсутствие единственного символа оказывает столь же значительное влияние на интерпретацию кода; выделяя "!" как единственный плохой не имеет смысла для меня.
Беван
5
@bevan Видимо, ты еще не укушен.
1
Хотя я согласен с тем, что упускание из виду !, вероятно, является наиболее неприятной ошибкой такого рода, это должно привести к тому, что ИМО не будет создавать привычку писать, ==falseа писать более качественные модульные тесты.
оставил около
8
@ ThorbjørnRavnAndersen Совсем наоборот - за эти годы меня укусили достаточно часто, чтобы научить себя читать каждый символ . Я не являюсь автором всего (или даже большей части) кода, который мне приходится читать изо дня в день, поэтому любое личное соглашение, которое мы обсуждаем здесь, имеет минимальное значение: мне нужно правильно понимать весь код, который я читаю, а не только то, что я написал.
Беван
13

Если для вас condition == falseэто действительно «намного более естественно на английском», то я должен предположить, что вы не являетесь носителем языка. В противном случае я не могу это объяснить, потому что никто не говорит так:

Если солнце светит ложно, я остаюсь дома.

Сравните это с

Если солнце не светит, я остаюсь дома.

Тем не менее, я согласен с тем, что единственный тонкий !персонаж легко игнорируется в коде. По этой причине я предпочитаю ключевое слово, notкогда оно поддерживается языком. C ++, например , позволяет это, хотя многие программисты не знают об этом.

Для языков, которые требуют !, я ставлю пробел между оператором и операндом. Это делает отрицание намного труднее пропустить:

if (! condition) { … }

Обратите внимание, что каждый программист должен переводить это автоматически , не задумываясь, на «не состояние» в своей голове. Приобретение этого вида беглости в чтении идиом кода является одним из первых шагов в становлении хорошего программиста.

Конрад Рудольф
источник
7

Когда я вижу, var == falseя всегда задаюсь вопросом, varявляется ли это логическим или логическим типом с более чем двумя значениями (например, a maybeи a, undefinedа также trueи falseили что-то вроде девяти значений IEEE 1164 ).

AProgrammer
источник
8
3-е значение обычно "Файл не найден". thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx
Groky
6

потому что иногда вы можете написать boolean = false(с очевидными ошибками) и false == booleanне кажется естественным (независимо от того, насколько это хорошо для практики)

чокнутый урод
источник
Давным-давно, когда я впервые начал программировать, мой наставник предложил мне привыкнуть if( INVALID_HANDLE_VALUE == hFile )избегать подобных вещей. Таким образом, если вы ошибетесь и используете один знак равенства вместо двух, вы получите ошибку компилятора. Очевидно, это работает только тогда, когда левое выражение является константой, но это спасло меня от головной боли, чем я могу сосчитать.
Дрю Чапин
Если вы используете инструмент статического анализа, он сэкономит вам в сто раз больше головных болей, и вы сможете восстановить характер hFile==INVALID_HANDLE_VALUE письма.
Gqqnbig
4

if (!boolean_variable)переводится как if the condition is not true.

if (boolean == false)переводится как if the condition not false is true. Поскольку это обратная логика, ее сложнее понять.

оборота BЈовић
источник
3
! правда означает не правда. ! boolean означает либо не false, либо не true в зависимости от значения логического значения, которое само по себе является логической инверсией.
С.Робинс
1
@ S.Robins Я нахожу глупое имя логического для логической переменной. Нечто подобное, например, isVisibleбудет лучшим примером. Тогда if (!isVisible)будет означать, если не видно - что проще для понимания, то if (isVisible==false)есть обратная логика. Надеюсь, теперь стало понятнее. Или я неправильно понял ваш комментарий?
BЈовић
2

Я полагаю, что в (гораздо) более старых компиляторах они будут разбиваться (boolean == false) на 2 назначения регистров и код сравнения на машинном языке. Первый пример будет разбит на одно присваивание и оператор NOT. С точки зрения производительности операция сравнения будет занимать несколько тактов в зависимости от размера сравниваемого регистра по сравнению с побитовым инвертированием (1 такт) и будет выполняться медленнее.

При этом, я считаю, что новые компиляторы покончат с этим, так что все должно быть в порядке.

lcllam
источник
Генерация машинного кода - это работа компилятора, а не программиста на языке высокого уровня ...
CVn
По историческим причинам это вполне может быть одной из причин, по которой один метод стал предпочтительнее другого.
Леголас
1

На работе я часто имею дело с логическими значениями, которые могут быть нулевыми, поэтому я буду часто кодировать этот случай как

if (value != null && value == true){
    //do something
}

потому что я лично чувствую, что симметрия облегчает чтение. Особенно, если есть и другие булевы тесты.

Мне действительно все равно, так или иначе.

WuHoUnited
источник
4
если value == trueнет причин проверять, что это не NULL. Если value == nullоно никогда не должно запускать оператор if, то этого if (value)должно быть достаточно.
zzzzBov
1
Логические значения являются объектами (в java) и поэтому могут иметь значение null, поэтому просто произнесение if (value)выдает исключение. Я был бы признателен, если бы люди, которые понизили голос, дали причину.
WuHoUnited
3
Я просто случайно увидел это, не понизил голос. Булево значение null не является хорошей практикой. Почему? потому что логическое значение обычно представляет состояние чего-то включенного или выключенного. В большинстве случаев вы хотели бы объявить это ложным в начале, а затем изменить его вместе с поведением. Очень редко можно видеть, что логическое значение не инициализируется.
баклажан
Я должен согласиться с Aubergine здесь, я сам впал в дурную привычку (особенно в Java) оставлять bool неинициализированными и затем заканчивать проверку на null. Я думаю, что это скорее недостаток языка, который навязывает этот недостаток пользователю. На мой взгляд, при объявлении новой переменной bool она должна по умолчанию иметь значение false без инициализации.
2
@WuHoUnited, даже если значение равно нулю, value == trueбудет достаточно.
zzzzBov
1

Когда вы тестируете истинное условие, имеет смысл выполнить это просто if (condition), особенно когда вы применяете соглашение о присвоении имен логическим переменным, начинающимся с 'is': if (isOpen)совершенно ясно и использование != falseбудет избыточным.

Для C / C ++ / Java / и т. Д. программист, значение «!» оператор полностью ассимилирован до такой степени, что мы автоматически имеем «не» в наших умах, когда видим его. Так что иметь if (!isOpen)так же ясно, как if (_NOT_ isOpen)для меня. Но вы недостаточно знакомы, в C / C ++ вы можете создать макрос с #define _NOT_ !. Но поверьте мне, через несколько лет это совершенно не нужно.

Кроме того, всегда предпочтительнее тестировать логические значения, не сравнивая их с литералами. Например, опасно проверять, if (x == true)потому что булево значение считается истинным, если оно не равно нулю, а литеральное истина имеет только одно конкретное значение, поэтому x может быть «истинным» (т. Е. Ненулевым), а сравнение все равно считается ложным (потому что оно содержит 2, и буквальное значение true, скажем, 1.) Конечно, это не относится к сравнению с false, но если вы не используете его при тестировании на true, зачем использовать его при тестировании на false?

оборота Фабио Секонелло
источник
Нет необходимости создавать предложенный вами макрос C ++, так как C ++ уже понимает «нет». Связанный: stackoverflow.com/questions/2393673/c-and-or-not-xor-keywords
frozenkoi
Это правда, но это ключевое слово только для стандарта C ++ 0X. До этого это был просто еще один макрос.
Фабио Секонелло
0

Размер имеет значение ;)

В смешанных выражениях легче читать:

boolean1 = false
boolean2 = true

p ! boolean1 and ! boolean2
p boolean1 == false and boolean2 == false

И особенно для ruby ​​пример, где это большая разница:

boolean = nil
p ! boolean         #-> true
p boolean == false  #-> false

ноль не ложь, но это также не правда.

Кнут
источник
0

Основываясь на моем опыте и ответах на мой вопрос, с которыми вы связались.

Некоторые люди предпочитают использовать if (условие), потому что оно короче, чтобы написать. и для меня это действительно имеет смысл, например (! isValidated ()) я читаю это как не подтверждено. но для меня все это основано на личных предпочтениях, и это зависит от логической структуры метода isValidated (), если он возвращает либо true, либо false

KyelJmD
источник
0

Если вы правильно назвали свою переменную, то !booleanэто более естественно. Он читается как not booleanлюбой, кому достаточно программиста, чтобы читать код мысленно.

Гонки легкости с Моникой
источник
0

Для некоторых людей, чем скорее будет выражен смысл, тем лучше.

Для тех людей, у которых «if! ...» сравнивается быстрее с «if ...», тогда приходится читать все условия (которые на самом деле могут быть довольно длинными, например (thisThing = thatThing или что-то = другое) ИЛИ ( thinga = thingb и thinga = thingd) и т. д.), просто чтобы найти == false в конце.

Прочитав! (Я на самом деле предпочитаю «нет», когда язык это позволяет), сразу же появляется английское «не» для этого условия.

Эта проблема также заставляет задуматься об использовании untilв языках, которые ее поддерживают, например, делать «обычные вещи» до тех пор, пока они не завершатся. Как говорят другие, целью является выражение на естественном языке. Мне нравится пример "солнце светит" выше.

наркоман
источник
0

Другая причина заключается в том, что если вы работаете в кодовой базе, которая использует несколько языков, если есть один идиоматический способ сделать что-то безопасное на всех языках, это хорошая идея сделать это везде так, чтобы у вас сформировалась хорошая привычка и с меньшей вероятностью споткнуться.

Я нигде не могу вспомнить, что if (!variable)(или эквиваленты, например, в if not variableзависимости от вашего языка) небезопасны, в то время как, например, if self.is_ready() == False: ...небезопасно в python, если self.is_ready()возвращается None, сейчас или в будущем, что было бы совершенно разумно для него сделать, чтобы указывают, что это не было готово, так Noneкак столь же фальшиво как False.

daphtdazz
источник