Dlaczego warto używać! Boolean_variable Over boolean_variable == false

59

Komentarz do tego pytania: Sprawdzanie, czy metoda zwraca false: przypisać wynik do zmiennej tymczasowej, czy bezpośrednio wywołać metodę w warunkowym? mówi, że powinieneś używać !booleanzamiast boolean == falsepodczas testowania warunków. Dlaczego? Dla mnie boolean == falsejest znacznie bardziej naturalny w języku angielskim i jest bardziej wyraźny. Przepraszam, czy to tylko kwestia stylu, ale zastanawiałem się, czy istnieje jakiś inny powód tego wyboru !boolean?

ell
źródło
28
Krótsze jest pisanie.
Zenon
39
To jak robienie boolean == true: to nie ma sensu. Wyrażenia wewnątrz ifinstrukcji to po prostu: wyrażenia. Jeśli coś już ocenia wyrażenie boolowskie, dlaczego miałbyś dodać czek, aby zmusić to do oceny?
Maks.
10
@zzzzBov: Um, no. Nie tak robi większość programistów (w stylu C).
amara,
9
@zzzzBov: Twój komentarz jest dwuznaczny. Jeśli miałeś na myśli, że !boolean_variabletak właśnie robi większość programistów C, zgadzam się.
Keith Thompson,
29
A co ważniejsze, dlaczego nikt nie chce pisać boolean != true?

Odpowiedzi:

153

Kiedy widzę taki wiersz if (!lateForMeeting()), czytam to jako „Jeśli nie spóźnię się na spotkanie” , co jest dość proste do zrozumienia, w przeciwieństwie do if (lateForMeeting() == false)tego, co przeczytałem jako „Jeśli fakt, że spóźnię się na spotkanie, jest fałszywy „ .

Mają one identyczne znaczenie, ale ten pierwszy jest bliżej tego, jak skonstruowane zostanie równoważne zdanie angielskie.

kba
źródło
27
+1 W Pythonie piszesz if not late_for_meeting:)
phunehehe
42
Twierdzę, że jeśli „jeśli ___ jest fałszywe” brzmi bardziej naturalnie niż „jeśli nie ___”, to nazwa ___ wymaga poprawy.
Mike DeSimone
12
W Perlu możesz pisaćunless late_for_meeting
Henrik Ripa
4
@HenrikRipa: Wygląda na to, że wszystko, co możesz wpisać, to legalny kod w Perlu. To, czy robi to, co chcesz, to kolejne pytanie;)
Adam Robinson
4
@ A-Cube Na początku nie miałbym takiej metody. Zamiast tego miałbym metodę o nazwie done(). Podwójne negatywy są złe.
kba
97

Pisanie == falsei == truejest zbędne. Można go również doprowadzić do arbitralności. Jeśli zaczniesz pisać

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

Więc czemu nie

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

A dlaczego nie

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

Morał tej historii jest taki, że jeśli conditionjest to wyrażenie boolowskie, to nie trzeba dodawać == false; po to !jest operator ;)

Andres F.
źródło
Nie myślałem o tym!
ell
51
== falseNIE jest zbędne, tylko bardziej szczegółowe niż !. OTOH == truejest zbędny.
dan04
4
@ dan04 Masz rację. Jednak w sensie, w jakim to miałem na myśli, pozostaje to zły pomysł. Rozważmy (exp1 != exp2)vs ((exp1 == exp2) == false). Wprawdzie są to wymyślone scenariusze, ale prawie nigdy nie powinieneś pisać wyraźnych porównań z prawdą lub fałszem. Tak jak powinieneś używać operatora !=, więc powinieneś używać !.
Andres F.
26
@ dan04: Jest zbędny, gdy język już oferuje !.
DeadMG,
5
@ dan04: Za każdym razem, gdy piszesz bool_expression == bool_literal, == ...jest ono zbędne. Nie ma znaczenia, czy testujesz na prawdę, czy na fałsz. To tylko zmiana kolejności następnych / alternatywnych bloków. Przykłady Andresa doskonale ilustrują ten punkt. Większość nowoczesnych kompilatorów zoptymalizuje nadmiarowość, ale nadal jest nadmiarowa.
Lèse majesté
70

W języku C i niektórych podobnych językach porównywanie wyrażeń boolowskich w celu zapewnienia równości falselub trueniebezpiecznego nawyku.

W języku C dowolne wyrażenie skalarne (numeryczne lub wskaźnikowe) może być użyte w kontekście logicznym, na przykład jako warunek ifinstrukcji. Reguła C if (cond)jest równoważna if (cond != 0)- tzn. Zero jest fałszem, a każda wartość niezerowa jest prawdą. Jeśli condjest typu wskaźnika, 0jest traktowane jako stała wskaźnika zerowego; if (ptr)oznacza if (ptr != NULL).

To znaczy że

if (cond)

i

if (cond == true)

nie oznaczają tego samego . Pierwszy jest prawdziwy, jeśli condjest niezerowy; druga jest prawdziwa tylko wtedy, gdy jest równa true, która w C (jeśli masz #include <stdbool.h>) jest po prostu 1.

Na przykład isdigit()funkcja zadeklarowana w <ctype.h>zwraca intwartość, 0jeśli argument jest cyfrą, niezerową, jeśli nie jest. Może powrócić, 42aby wskazać, że warunek jest spełniony. Porównywanie 42 == truezakończy się niepowodzeniem.

Zdarza się, że 0jest to jedyna wartość uważana za fałszywą, więc porównanie równości falsezadziała; if (!cond)i if (cond == false)rób to samo. Ale jeśli zamierzasz to wykorzystać, musisz pamiętać, że porównywanie falsejest w porządku, a porównywanie truenie. Co gorsza, w porównaniu do truebędzie działać przez większość czasu (na przykład operatory równości i relacyjne zawsze dają albo 0albo 1). Oznacza to, że wszelkie błędy, które wprowadzisz, używając tego nadal mogą być trudne do wyśledzenia. (Nie martw się, pojawią się, gdy tylko zadasz kod ważnemu klientowi).

C ++ ma nieco inne reguły; na przykład jego booltyp jest nieco ściślej zintegrowany z językiem i if (cond)konwertuje się condna typ bool. Ale efekt jest (przeważnie) taki sam.

Niektóre inne języki mają coś, co można by nazwać lepiej zachowującymi się wartościami logicznymi, na przykład cond == truei cond == false(lub jakakolwiek inna składnia się zdarzy) jest bezpieczne. Mimo to każdy język, który widziałem, ma operatora notlub !; jest tam, więc równie dobrze możesz go użyć. Używanie cond == falsezamiast !condlub not cond, moim zdaniem, nie poprawia czytelności. (Prawdą jest, że !postać może być trudna do zobaczenia na pierwszy rzut oka; czasem dodaję spację, !aby tego uniknąć).

Często można uniknąć tego problemu i poprawić przejrzystość, zmieniając nieco kod. Na przykład zamiast:

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

możesz napisać:

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

Nie zawsze jest to lepsze, ale nie zaszkodzi szukać okazji tam, gdzie jest.

Podsumowanie: W C i C ++ porównania równości truei falsesą niebezpieczne, zbyt szczegółowe i kiepskie. W wielu innych językach takie porównania mogą nie być niebezpieczne, ale wciąż są zbyt szczegółowe i kiepskie.

Keith Thompson
źródło
+1 za to, że jest to jedyna odpowiedź z faktycznie przydatnym wyjaśnieniem technicznym.
Mike Nakis
Nadal tak myślę, niezależnie od języka programowania, który zawsze uważam za == trueniebezpieczny. W ten sposób czuje się lepiej.
Dervall,
1
@Dervall: zakładanie czegoś, co po prostu nie jest przypadkiem, również nie jest dobre. Istnieje kilka przypadków narożnych w niektórych językach, w których porównanie równości boolean jest nie tylko bezpieczne, ale w rzeczywistości właściwe, na przykład w Haskell, który ma silny niejawny system rzutowania z dwukierunkowym wnioskowaniem o typ, można napisać, (==True) . faby wyjaśnić, że chcemy -> Boolinstancji funkcji powrotu-polimorfu f. To jest jaśniejsze niż not . not . fi mniej niezręczne niż (f :: a -> Bool).
lewo wokół
Z pewnością właściwe jest robienie rzeczy takich jak pred(x)==pred(y)funkcja zwracająca bool pred. Alternatywa, pred(x)? pred(y) : !pred(y)którą zgodzisz się, jest prawie nie do przyjęcia.
lewo wokół
1
@leftaroundabout: W porządku, jeśli o tym wiesz pred(x)i pred(y)używaj tej samej wartości do oznaczenia prawdy, co jest bezpiecznym założeniem w niektórych językach, ale w innych nie. Na przykład w C możesz pisać !!pred(x) == !!pred(y).
Keith Thompson
13

Jeśli condition == falserzeczywiście jest to dla ciebie „znacznie bardziej naturalne”, muszę założyć, że nie jesteś native speakerem. W przeciwnym razie nie mogę tego wyjaśnić, ponieważ nikt tak nie mówi:

Jeśli świeci słońce, to nieprawda, zostaję w domu.

Porównaj to z

Jeśli słońce nie świeci, zostaję w domu.

To powiedziawszy, zgadzam się, że pojedynczy, smukły !znak jest łatwo przeoczony w kodzie. Z tego powodu wolę słowo kluczowe, notjeśli jest obsługiwane przez język. C ++ na przykład nie pozwala na to, choć wielu programistów nie są tego świadomi.

W przypadku języków, które tego wymagają !, wstawiam spację między operatorem a operandem. To sprawia, że ​​negacja jest o wiele trudniejsza do przeoczenia:

if (! condition) { … }

Zauważ, że każdy programista powinien przetłumaczyć to automatycznie , bez namysłu, na „brak warunku” w głowie. Zdobycie tego rodzaju biegłości w odczytywaniu idiomów kodu jest jednym z pierwszych kroków do zostania dobrym programistą.

Konrad Rudolph
źródło
13

Oba są funkcjonalnie identyczne, więc który z nich należy do gustu.

Głównym powodem, którego używam, == falsejest to, że stwierdziłem, że !jest zbyt łatwy do przeoczenia, patrząc na kod.

Po tym, jak zostałem poważnie ugryziony, przyzwyczaiłem się dawać to do zrozumienia podczas testowania na fałsz.


Gdyby operator został nazwany nottak jak w Pascalu, nie sądzę, aby stałoby się to problemem.

1249
źródło
5
Z tego właśnie powodu projekt C ++, nad którym pracowałem dla jakiegoś oprogramowania urządzeń medycznych, miał standard kodowania, który nakazał == falsezamiast z !tego samego powodu (aby wyróżnić się). Jednak nie było wymogu używania == true, więc każda niezerowa wartość nadal działała tak, jak powinna.
tcrosley
12
Zawsze uważałem ten argument za nieprzekonujący - w C / C ++ / C # / Java / itp. Są inne miejsca, w których brak dostrzeżenia pojedynczego znaku ma podobny znaczący wpływ na interpretację kodu; Wyodrębnić "!" ponieważ jedyny zły nie ma dla mnie sensu.
Bevan
5
@bevan Najwyraźniej jeszcze nie zostałeś ugryziony.
1
Chociaż zgadzam się, że przeoczenie !jest prawdopodobnie najbardziej kłopotliwym błędem tego rodzaju, to IMO nie powinno powodować nawyku pisania, ==falseale pisania lepszych testów jednostkowych.
leftaroundabout
8
@ ThorbjørnRavnAndersen Wręcz przeciwnie - gryzłem dość często przez lata, że ​​nauczyłem się czytać każdą postać . Nie jestem autorem całego (a nawet większości) kodu, który muszę czytać każdego dnia, więc każda konwencja osobista, o której tu mówimy, ma minimalną wartość: muszę poprawnie zrozumieć cały kod, który czytam, a nie tylko rzeczy, które napisałem.
Bevan
6

ponieważ czasami możesz pisać boolean = false(z oczywistymi błędami) i false == booleannie wydaje się to naturalne (bez względu na to, jak dobra jest praktyka)

maniak zapadkowy
źródło
Dawno, dawno temu, kiedy zacząłem programować, mój mentor zasugerował, że mam w zwyczaju if( INVALID_HANDLE_VALUE == hFile )unikać takich rzeczy. W ten sposób, jeśli wpadniesz w poślizg i użyjesz jednego znaku równości zamiast dwóch, pojawi się błąd kompilatora. Oczywiście działa to tylko wtedy, gdy lewy wyraz jest stały, ale zaoszczędził mi więcej bólów głowy, niż mogę zliczyć.
Drew Chapin
jeśli użyjesz narzędzia do analizy statycznej, zaoszczędzi to sto razy więcej bólu głowy i będziesz w stanie przywrócić charakter hFile==INVALID_HANDLE_VALUE pisma.
Gqqnbig,
4

if (!boolean_variable)przekłada się na if the condition is not true.

if (boolean == false)przekłada się na if the condition not false is true. Ponieważ jest to odwrócona logika, trudniej ją zrozumieć.

rev BЈовић
źródło
3
! prawda oznacza nieprawdę. ! boolean oznacza albo nie fałsz, albo nieprawda w zależności od wartości boolean, która sama w sobie jest logiczną inwersją.
S.Robins
1
@ S.Robins Znajduję głupią nazwę boolean dla zmiennej boolean. Coś takiego jak na przykład isVisiblebyłoby lepszym przykładem. Wtedy if (!isVisible)oznaczałoby jeśli nie widać - co jest prostsze do zrozumienia czym if (isVisible==false), co jest odwrotna logika. Mam nadzieję, że teraz jest wyraźniej. A może źle zrozumiałem twój komentarz?
BЈовић
2

Wierzę, że w (dużo) starszych kompilatorach rozdzieliłyby (boolean == false) na 2 przypisania rejestrów i kod porównawczy w języku maszynowym. Pierwszy przykład zostałby podzielony na jedno przypisanie i operator NOT. Pod względem wydajności operacja porównania wymagałaby szeregu cykli zegara, w zależności od wielkości porównywanego rejestru, w porównaniu z odwróceniem bitowym (1 zegar) i byłaby wolniejsza do wykonania.

Biorąc to pod uwagę, uważam, że nowsze kompilatory zlikwidują to, więc powinno być OK, aby wybrać jedno z nich.

lcllam
źródło
Generowanie kodu maszynowego jest zadaniem kompilatora, a nie programisty wysokiego poziomu ...
CVn
Z przyczyn historycznych może to być jeden z powodów, dla których jedna metoda stała się preferowana.
Legolas
1

W pracy często mam do czynienia z booleanami, które mogą być zerowe, więc często koduję tę sprawę jako

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

ponieważ osobiście uważam, że symetria ułatwia czytanie. Zwłaszcza jeśli testowane są również inne booleany.

Nie obchodzi mnie to w ten czy inny sposób.

WuHoUnited
źródło
4
jeśli value == truewtedy nie ma powodu, aby sprawdzić, czy nie jest to wartość zerowa. Jeśli value == nullnigdy nie powinien wywoływać instrukcji if, to if (value)powinno wystarczyć.
zzzzBov
1
Wartości logiczne są obiektami (w java) i dlatego mogą być zerowe, więc samo powiedzenie if (value)generuje wyjątek. Byłbym wdzięczny, gdyby ludzie, którzy oddali głos, podali powód.
WuHoUnited
3
Po prostu akurat to widziałem, nie przegłosowałem. Wartość logiczna null nie jest dobrą praktyką. Dlaczego? boolean zwykle oznacza stan czegoś włączonego i wyłączonego. W większości przypadków na początku chciałbyś uznać je za fałszywe, a następnie zmienić wraz z zachowaniem. Bardzo rzadko zdarza się, że inicjalizacja wartości logicznej nie jest inicjowana.
Bakłażan
Muszę się tutaj zgodzić z Aubergine, sam popadłem w zły nawyk (szczególnie w Javie) pozostawiania boin niezainicjowanych, a potem sprawdzania, czy nie ma wartości zerowej. Myślę, że to bardziej wada języka, która jednak nakłada tę wadę na użytkownika. Deklarując nową zmienną bool, moim zdaniem powinna ona domyślnie przyjmować wartość false bez inicjalizacji.
2
@WuHoUnited, nawet gdyby wartość była null, value == truebyłaby wystarczająca.
zzzzBov
1

Kiedy testujesz prawdziwy warunek, warto to zrobić if (condition), zwłaszcza gdy zastosujesz konwencję nazewnictwa zmiennych boolowskich zaczynającą się od „is”: if (isOpen)jest całkowicie jasne, a użycie != falsebyłoby zbędne.

Dla C / C ++ / Java / itp. programista, znaczenie „!” operator jest całkowicie zasymilowany do tego stopnia, że ​​automatycznie widzimy „nie” w naszych umysłach. Więc posiadanie if (!isOpen)jest tak samo jasne jak if (_NOT_ isOpen)dla mnie. Ale nie jesteś wystarczająco zaznajomiony, w C / C ++ możesz utworzyć makro #define _NOT_ !. Ale zaufaj mi, po kilku latach jest to całkowicie niepotrzebne.

Poza tym zawsze lepiej jest testować wartości logiczne bez porównywania ich z literałami. Na przykład niebezpieczne jest testowanie, if (x == true)ponieważ wartość logiczna jest uważana za prawdę, jeśli nie jest zerowa, a dosłowna prawda ma tylko jedną określoną wartość, więc x może być „prawda” (tj. Niezerowa), a porównanie porównuje wartość fałszywą (ponieważ zawiera 2, a dosłowna prawda to, powiedzmy, 1). Oczywiście nie dotyczy to porównania z fałszem, ale jeśli nie użyjesz go podczas testowania na prawdę, po co używać go podczas testowania na fałsz?

Fabio Ceconello
źródło
Nie jest konieczne, aby makro C ++, które proponujesz, ponieważ C ++ już rozumie „nie”. Powiązane: stackoverflow.com/questions/2393673/c-and-or-not-xor-ke
words
To prawda, ale jest to słowo kluczowe tylko dla standardu C ++ 0X. Wcześniej było to tylko kolejne makro.
Fabio Ceconello
0

Rozmiar ma znaczenie ;)

W wyrażeniach mieszanych łatwiej jest przeczytać:

boolean1 = false
boolean2 = true

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

I szczególnie dla ruby ​​przykład, gdzie jest duża różnica:

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

zero nie jest fałszywe, ale także nie jest prawdą.

knut
źródło
0

Na podstawie mojego doświadczenia i odpowiedzi na moje pytania, z którymi się powiązałeś.

Niektóre osoby wolą używać if (warunek), ponieważ powodem jest to, że jest krótszy do napisania. i dla mnie to ma sens, na przykład (! isValidated ()) Przeczytałem to jako Not Validated. ale dla mnie wszystko opiera się na osobistych preferencjach i zależy od logicznej struktury metody isValidated (), jeśli zwróci true lub false

KyelJmD
źródło
0

Jeśli poprawnie nazwałeś swoją zmienną, !booleanjest to bardziej naturalne. Odczytuje jak not booleankażdy, kto ma dość programisty, aby czytać kod w myślach.

Lekkość Wyścigi na orbicie
źródło
0

Dla niektórych ludzi im wcześniej zostanie to określone, tym lepiej.

Dla tych, którzy mają „jeśli! ...” porównuje się szybciej do „jeśli ...”, to muszą przeczytać cały warunek (który może być naprawdę długi, np. (ThisThing = thatThing lub coś = inna rzecz) LUB ( thinga = thingb i thinga = thingd) itd.), aby znaleźć == false na końcu.

Posiadanie! (Właściwie wolę „nie”, gdy pozwala na to język). Natychmiast pojawia się angielskie „nie” dla tego warunku.

Ten problem prowadzi również do rozważenia używania go untilw językach, które go obsługują, np. Rób „typowe rzeczy”, dopóki coś się nie zakończy. Jak mówią inni, celem jest ekspresja języka naturalnego. Podoba mi się powyższy przykład „słońce świeci”.

śmieciowy
źródło
0

Innym powodem jest to, że jeśli pracujesz w bazie kodu, która używa kilku języków, jeśli istnieje jeden idiomatyczny sposób na zrobienie czegoś, co jest bezpieczne we wszystkich językach, całkiem dobrym pomysłem jest zrobienie tego w ten sposób wszędzie, aby stworzyć dobry nawyk i rzadziej się potkną.

Nie mogę wymyślić nigdzie, co if (!variable)(lub odpowiedniki, takie jak if not variablezależnie od twojego języka) nie jest bezpieczne, podczas gdy np. if self.is_ready() == False: ...Nie jest bezpieczny w Pythonie, jeśli self.is_ready()powróci None, teraz lub w przyszłości, co byłoby całkowicie rozsądnym rozwiązaniem wskazują, że nie był gotowy, ponieważ Nonejest tak samo falsey jak False.

daphtdazz
źródło