Dlaczego dokładnie Java nie dopuszcza warunkowych liczb, takich jak if (5) {…}, jeśli C to robi?

33

Mam te dwa małe programy:

do

#include <stdio.h>
int main()
{
    if (5) {
        printf("true\n");
    }
    else {
        printf("false\n");
    }

    return 0;
}

Jawa

class type_system {
   public static void main(String args[]) {
       if (5) {
           System.out.println("true");
       }
       else {
           System.out.println("false");
       }
   }
}

który zgłasza komunikat o błędzie:

type_system.java:4: error: incompatible types: int cannot be converted to boolean
       if (5) {
           ^
1 error

Moje zrozumienie

Do tej pory rozumiałem ten przykład jako demonstrację różnych systemów typów. C jest słabiej wpisany i pozwala na konwersję z int na boolean bez błędów. Java jest silniej typowana i kończy się niepowodzeniem, ponieważ niedozwolona jest niejawna rozmowa.

Dlatego moje pytanie: gdzie źle zrozumiałem?

Czego nie szukam

Moje pytanie nie dotyczy złego stylu kodowania. Wiem, że to źle, ale interesuje mnie, dlaczego C na to pozwala, a Java nie. Dlatego interesuje mnie system typów języka, a konkretnie jego siła.

toogley
źródło
22
@toogley: co konkretnie chcesz wiedzieć o systemie typów w Javie? System typów nie pozwala na to, ponieważ specyfikacja języka tego zabrania. Powody, dla których C na to pozwala, a Java nie ma wszystkiego wspólnego z tym, co uważa się za dopuszczalne w obu językach. Wynikowe zachowanie systemów typów jest skutkiem tego, a nie przyczyną.
Robert Harvey
8
@toogley: jak myślisz, dlaczego coś źle zrozumiałeś? Czytając ponownie tekst, nie rozumiem, jakie jest twoje pytanie.
Doc Brown
26
W rzeczywistości nie jest to przykład słabego pisania w C. W przeszłości (C89) C nie miał nawet typu logicznego, więc wszystkie operacje „logiczne” faktycznie działały na intwartościach. Bardziej właściwym przykładem byłby if (pointer).
Rufflewind
5
Odrzuciłem głos, ponieważ nie wydaje się, aby przeprowadzono wiele badań, próbując to zrozumieć.
jpmc26
11
Wygląda na to, że pierwotne pytanie jest nieco inne niż wersja edytowana (dlatego niektóre komentarze i odpowiedzi wydają się odpowiadać na inne pytania). W obecnej formie wydaje się, że nie ma tu pytania. Jakie nieporozumienie? Java działa dokładnie tak, jak myślisz, że powinna być.
jamesdlin

Odpowiedzi:

134

1. C i Java to różne języki

Fakt, że zachowują się inaczej, nie powinien być strasznym zaskoczeniem.

2. C nie dokonuje żadnej konwersji z intnabool

Jak to możliwe? C nie miał nawet prawdziwego booltypu do konwersji do 1999 roku . C został stworzony w roku 1970 i ifbyła częścią zanim było nawet C, z powrotem, gdy była to tylko seria modyfikacji B 1 .

ifnie był po prostu NOPw C przez prawie 30 lat. Działał bezpośrednio na wartości liczbowe. Verbage w standardzie C ( link PDF ), nawet ponad dekadę po wprowadzeniu bools do C, nadal określa zachowanie if(p 148) i ?:(p 100) przy użyciu terminów „nierówne do 0” i „równe 0” ”zamiast boolowskich określeń„ prawda ”lub„ fałsz ”lub coś podobnego.

Dogodnie ...

3. ... liczby są akurat tymi, na których działają instrukcje procesora.

JZi JNZsą podstawowymi instrukcjami montażu x86 dla warunkowego rozgałęziania. Skróty to „ J ump if Z ero” i „ J ump if N ot Z ero”. Odpowiedniki dla PDP-11, przy czym C pochodzi są BEQ( " B Ranch jeśli EQ UAL ") i BNE(" B Ranch jeśli N OT E qual").

Instrukcje te sprawdzają, czy poprzednia operacja zakończyła się zerem, czy też nie i odpowiednio przeskakują (lub nie).

4. Java kładzie większy nacisk na bezpieczeństwo niż C kiedykolwiek 2

I mając na uwadze bezpieczeństwo, zdecydowali, że ograniczenie ifdo booleans było warte kosztów (zarówno wdrożenie takiego ograniczenia, jak i wynikające z tego koszty alternatywne).


1. B w ogóle nie ma typów. Języki asemblera też ogólnie nie. Jednak B i asemblery radzą sobie doskonale z rozgałęzianiem.

2. Słowami Dennisa Ritchiego przy opisywaniu planowanych modyfikacji B, które stały się C (moje podkreślenie):

... wydawało się, że schemat pisania jest konieczny, aby poradzić sobie ze znakami i adresowaniem bajtów oraz przygotować się na nadchodzący zmiennoprzecinkowy sprzęt. Inne kwestie, w szczególności bezpieczeństwo typu i kontrola interfejsu, nie wydawały się wtedy tak ważne, jak stały się później.

8bittree
źródło
13
Fajna uwaga na temat wyrażeń boolowskich w odwzorowaniu C bezpośrednio na instrukcje procesora. Nie myślałem o tym wcześniej.
Robert Harvey
17
Myślę, że punkt 4 jest mylący, ponieważ wydaje się sugerować, że C ma pewne poczucie bezpieczeństwa ... C pozwoli ci robić zasadniczo wszystko, co chcesz: C zakłada, że ​​wiesz, co robisz, często do spektakularnych katastrof.
TemporalWolf
13
@TemporalWolf Stwierdzasz, że C pozwolenie ci na robienie tego, co chcesz było złe. Moim zdaniem różnica polega na tym, że C napisano dla programistów i oczekuje się podstawowych kompetencji. Java jest napisana dla małp kodowych i jeśli możesz pisać, możesz w niej programować. Często spektakularnie źle, ale kogo to obchodzi? Nigdy nie zapomnę, że nauczyciel we wstępnej klasie java, który musiałem wziąć jako część mojej młodszej CS, zwrócił uwagę, że użycie rekurencji do obliczenia liczb Fibonnaci może być przydatne, ponieważ jest „łatwe do napisania”. Właśnie dlatego mamy oprogramowanie, które mamy.
DRF
25
@DRF Jeden z moich profesorów klasy C powiedział: „C jest jak pudełko granatów ręcznych z wyciągniętymi szpilkami”. Masz dużo mocy, ale w zasadzie jest to gwarancją wysadzenia ci w twarz. W większości przypadków nie jest to kłopotliwe, a dzięki wyższemu poziomowi będziesz o wiele bardziej produktywny. Czy transkodowałem Pythona w hacky kręcenie bitów C, aby uzyskać wzrost prędkości o 6 rzędów wielkości? Tak, tak mam. Ale to wyjątek, a nie reguła. Mogę osiągnąć w ciągu jednego dnia w Pythonie, co zajęłoby mi dwa tygodnie w C ... i jestem przyzwoitym programistą C.
TemporalWolf
11
@DRF Biorąc pod uwagę występowanie przepełnienia bufora w oprogramowaniu głównego nurtu opracowanym przez najlepsze firmy, najwyraźniej nawet programiści posiadający podstawowe kompetencje nie mogą ufać, że nie zejdą z nóg.
Przywróć Monikę
14

C 2011 Online Draft

6.8.4.1 if

Ograniczenia instrukcji

1 Wyrażenie kontrolne ifinstrukcji powinno mieć typ skalarny.

Semantyka

2 W obu postaciach pierwsze podstawienie jest wykonywane, jeśli wyrażenie porównuje nierówne do 0. W elseformularzu drugie podstawienie jest wykonywane, jeśli wyrażenie porównuje się równe 0. Jeśli pierwsze podstawienie jest osiągane poprzez etykietę, drugie podstawienie jest nie wykonany.

3 An elsejest powiązany z leksykalnie najbliższym poprzedzającym, jeśli pozwala na to składnia.

Zauważ, że ta klauzula określa tylko, że wyrażenie kontrolne powinno mieć typ skalarny ( char/ short/ int/ long/ itp.), A nie konkretnie typ boolowski. Gałąź jest wykonywana, jeśli wyrażenie kontrolne ma niezerową wartość.

Porównaj to z

Specyfikacja języka Java SE 8

14.9 ifOświadczenie zestawienie umożliwia warunkowe wykonanie instrukcji lub warunkowego wyboru dwa sprawozdania, realizując jedną lub drugą stronę, ale nie jednocześnie.

if
    IfThenStatement :Instrukcja 
        if ( Expression )

    IfThenElseStatement :
        if ( Expression ) StatementNoShortIf else Instrukcja

    IfThenElseStatementNoShortIf :
        if ( Wyrażenie ) StatementNoShortIf else StatementNoShortIf
Wyrażenie musi mieć typ booleanlub Boolean, lub wystąpi błąd podczas kompilacji.

Java, OTOH, w szczególności wymaga, aby wyrażenie sterujące w ifinstrukcji było typu logicznego.

Nie chodzi więc o pisanie słabe vs. mocne, chodzi o to, co każda definicja języka określa jako prawidłowe wyrażenie kontrolne.

Edytować

Co do tego, dlaczego języki różnią się pod tym względem, kilka punktów:

  1. C pochodzi od B, który był językiem „beztypowym” - w zasadzie wszystko było 32- do 36-bitowym słowem (w zależności od sprzętu), a wszystkie operacje arytmetyczne były operacjami liczb całkowitych. System typu C był po kolei przykręcony, tak że ...

  2. C nie miał wyraźnego typu logicznego aż do wersji językowej z 1999 roku. C po prostu postępował zgodnie z konwencją B polegającą na użyciu zera do reprezentowania falsei niezerowego do reprezentowania true.

  3. Java wypada po C przez kilka dziesięcioleci i została zaprojektowana specjalnie w celu usunięcia niektórych niedociągnięć C i C ++. Bez wątpienia zaostrzenie ograniczenia wyrażenia kontrolnego w ifinstrukcji było częścią tego.

  4. Nie ma żadnego powodu, by spodziewać się jakieś dwa języki programowania robić rzeczy w ten sam sposób. Nawet języki tak blisko spokrewnione jak C i C ++ różnią się w kilka interesujących sposobów, na przykład, że możesz mieć legalne programy C, które nie są legalnymi programami C ++ lub są legalnymi programami C ++, ale o innej semantyce itp.

John Bode
źródło
Zbyt smutne, nie mogę oznaczyć dwóch odpowiedzi jako „zaakceptowane” ..
toogley
1
Tak, to dobre powtórzenie pytania. Pytanie brzmiało jednak, dlaczego istnieje różnica między tymi dwoma językami. W ogóle nie rozwiązałeś tego problemu.
Dawood mówi, że przywróć Monikę
@DawoodibnKareem: Pytanie brzmiało, dlaczego C zezwolił na konwersję od intdo, booleanpodczas gdy Java nie. Odpowiedź jest taka, że ​​nie ma takiej konwersji w C. Języki są różne, ponieważ są różnymi językami.
John Bode
Tak, „nie chodzi o słabe vs. mocne pisanie”. Wystarczy spojrzeć na automatyczne boxowanie i automatyczne rozpakowywanie. Gdyby C je posiadał, nie pozwoliłby na żaden typ skalara.
Deduplicator
5

Wiele odpowiedzi wydaje się dotyczyć osadzonego wyrażenia przypisania, które znajduje się w wyrażeniu warunkowym. (Chociaż jest to znany rodzaj potencjalnej pułapki, w tym przypadku nie jest on źródłem komunikatu o błędzie Java).

Być może dzieje się tak, ponieważ OP nie opublikował rzeczywistego komunikatu o błędzie, a ^daszek wskazuje bezpośrednio na =operatora przypisania.

Jednak kompilator wskazuje na to, =że to operator generuje wartość końcową (a zatem i typ końcowy) wyrażenia, które widzi warunek.

Narzeka na testowanie wartości innej niż boolowska, z następującym rodzajem błędu:

błąd: niezgodne typy: int nie można przekonwertować na wartość logiczną

Testowanie liczb całkowitych, choć czasem wygodne, jest uważane za potencjalną pułapkę, której projektanci Java chcą uniknąć. W końcu Java ma prawdziwy typ danych logicznych , którego C nie ma (nie ma typu logicznego) .

Odnosi się to również do wskaźników testowych języka C dla wartości zerowej / innej niż null przez if (p) ...i if (!p) ..., których Java podobnie nie pozwala, a zamiast tego wymaga jawnego operatora porównania w celu uzyskania wymaganej wartości logicznej.

Erik Eidt
źródło
1
C ma mieć typ boolean. Ale to nowsze niż ifstwierdzenie.
MSalters
3
Bool @MSalters C jest nadal liczbą całkowitą pod przykryciem, więc możesz to zrobić bool b = ...; int v = 5 + b;. Różni się to od języków z pełnym typem logicznym, których nie można używać w arytmetyce.
Jules
Wartość logiczna C jest po prostu bardzo małą liczbą całkowitą. „prawda” i „fałsz” można łatwo zdefiniować za pomocą makr lub cokolwiek innego.
Oskar Skog
4
@Jules: Wskazujesz tylko, że C ma słabe bezpieczeństwo typu. To, że typ boolowski przekształca się na wartość całkowitą, nie oznacza, że jest to typ całkowity. Według twojej logiki typy całkowite byłyby typami zmiennoprzecinkowymi, ponieważ int v = 5; float f = 2.0 + v;jest to dozwolone w C.
MSalters
1
@MSalters _Booljest w rzeczywistości jednym ze standardowych typów całkowitych bez znaku, zgodnie z definicją podaną przez Standard (patrz 6.2.5 / 6).
Ruslan
2

niekompatybilne typy: int nie może zostać przekonwertowany na wartość logiczną

Interesuje mnie, dlaczego C na to pozwala, a java nie. Dlatego interesuje mnie system typów języka, a konkretnie jego siła.

Twoje pytanie składa się z dwóch części:

Dlaczego Java nie konwertować intdo boolean?

Sprowadza się to do tego, że Java ma być jak najbardziej jawna. Jest bardzo statyczny, bardzo „prosto w twarz” dzięki systemowi typów. Rzeczy, które są automatycznie rzutowane na czcionkę w innych językach, nie są tak w Javie. Ty też musisz pisać int a=(int)0.5. Konwersja floatna intutraciłaby informacje; to samo, co konwersja intna, booleani dlatego byłaby podatna na błędy. Ponadto musieliby określić wiele kombinacji. Jasne, te rzeczy wydają się oczywiste, ale zamierzały popełnić błąd po stronie ostrożności.

Aha, w porównaniu z innymi językami, Java była bardzo dokładna w specyfikacji, ponieważ kod bajtowy nie był tylko wewnętrznym szczegółem implementacji. Musieliby dokładnie sprecyzować wszelkie interakcje. Ogromne przedsięwzięcie.

Dlaczego ifnie akceptuje innych typów niż boolean?

ifmożna idealnie zdefiniować jako pozwalające na inne typy niż boolean. Może mieć definicję, która mówi, że następujące są równoważne:

  • true
  • int != 0
  • String z .length>0
  • Wszelkie inne odwołania do obiektów, które nie są null(a nie Booleanmają wartości false).
  • Lub nawet: każde inne odwołanie do obiektu, które nie jest nulli którego metoda Object.check_if(wymyślona przeze mnie na tę okazję) zwraca true.

Nie zrobili tego; nie było takiej potrzeby i chcieli, aby był jak najbardziej solidny, statyczny, przezroczysty, łatwy do odczytania itp. Brak ukrytych funkcji. Ponadto implementacja byłaby dość złożona, jestem pewien, że musiałbym przetestować każdą wartość dla wszystkich możliwych przypadków, więc wydajność mogła również mieć niewielki wpływ (Java na komputerach tego dnia była powolna; pamiętaj, że tam nie było żadnych kompilatorów JIT z pierwszymi wydaniami, przynajmniej nie na komputerach, z których wtedy korzystałem).

Głębszy powód

Głębszym powodem może być fakt, że Java ma swoje prymitywne typy, dlatego system typów jest rozdarty między obiektami a prymitywami. Może gdyby tego uniknęli, sprawy potoczyłyby się inaczej. Zgodnie z regułami podanymi w poprzedniej sekcji musieliby jednoznacznie zdefiniować prawdziwość każdego pojedynczego elementu pierwotnego (ponieważ elementy podstawowe nie dzielą superklasy , a elementy podstawowe nie są dobrze zdefiniowane null). To szybko zamieniłoby się w koszmar.

Perspektywy

Cóż, w końcu może to tylko preferencja projektantów języków. Każdy język wydaje się kręcić własną drogą ...

Na przykład Ruby nie ma prymitywnych typów. Wszystko, dosłownie wszystko, jest przedmiotem. Mają bardzo łatwy czas, upewniając się, że każdy obiekt ma określoną metodę.

Ruby szuka prawdziwości we wszystkich typach przedmiotów, które możesz na nią rzucić. Co ciekawe, nadal nie ma booleantypu (ponieważ nie ma prymitywów), a także nie ma Booleanklasy. Jeśli zapytasz, jaką klasę truema wartość (łatwo dostępna true.class), otrzymasz TrueClass. Ta klasa faktycznie ma metody, a mianowicie 4 operatory dla booleanów ( | & ^ ==). Tutaj ifuważa , że jego wartość falsey jest wtedy i tylko wtedy, gdy jest to falsealbo nil( nullRuby). Wszystko inne jest prawdą. Tak więc 0lub ""obie są prawdą.

Byłoby dla nich trywialne stworzenie metody, Object#truthy?którą można by wdrożyć dla każdej klasy i zwrócić indywidualną prawdę. Na przykład, String#truthy?mógł zostać zaimplementowany, aby był prawdziwy dla niepustych ciągów znaków lub w ogóle. Nie zrobili tego, chociaż Ruby jest antytezą Javy w większości działów (dynamiczne pisanie kaczek z mixinem, ponowne otwieranie klas i tak dalej).

Co może być zaskakujące dla programisty Perla, który jest przyzwyczajony do $value <> 0 || length($value)>0 || defined($value)bycia prawdomównym. I tak dalej.

Wpisz SQL zgodnie z konwencją, że nullwewnątrz dowolnego wyrażenia automatycznie powoduje, że jest ono fałszywe, bez względu na wszystko. Tak (null==null) = false. W Ruby (nil==nil) = true. Szczęśliwe czasy.

AnoE
źródło
W rzeczywistości ((int)3) * ((float)2.5)jest dość dobrze zdefiniowany w Javie (tak jest 7.5f).
Paŭlo Ebermann
Masz rację, @ ​​PaŭloEbermann, usunąłem ten przykład.
AnoE
Wow, docenilibyśmy komentarze od downvoters i tego, który głosował za usunięciem odpowiedzi.
AnoE
W rzeczywistości konwersja z intna floatrównież traci informacje w ogóle. Czy Java również zabrania takiej niejawnej obsady?
Ruslan
@ Ruslan nie (to samo dla długiego → podwójnego) - Chyba chodzi o to, że potencjalna utrata informacji występuje tylko w najmniej znaczących miejscach i zdarza się tylko w przypadkach, które są uważane za mało ważne (dość duże wartości całkowite).
Paŭlo Ebermann
1

Oprócz innych dobrych odpowiedzi chciałbym porozmawiać o spójności między językami.

Kiedy myślimy o matematycznie czystym wyrażeniu if, rozumiemy, że warunek może być prawdziwy lub fałszywy, bez żadnej innej wartości. Każdy główny język programowania szanuje ten matematyczny ideał; jeśli podasz logiczną wartość prawda / fałsz instrukcji if, możesz spodziewać się spójnego, intuicyjnego zachowania przez cały czas.

Jak na razie dobrze. To właśnie implementuje Java i tylko to, co implementuje Java.

Inne języki starają się zapewnić udogodnienia dla wartości niebędących wartościami logicznymi. Na przykład:

  • Załóżmy, że njest liczbą całkowitą. Zdefiniuj teraz if (n)jako skrót if (n != 0).
  • Załóżmy, że xjest liczbą zmiennoprzecinkową. Zdefiniuj teraz if (x)jako skrót if (x != 0 && !isNaN(x)).
  • Załóżmy, że pjest to typ wskaźnika. Zdefiniuj teraz if (p)jako skrót if (p != null).
  • Załóżmy, że sjest to typ ciągu. Teraz zdefiniuj if (s)być if (s != null && s != "").
  • Załóżmy, że ajest typem tablicy. Teraz zdefiniuj if (a)być if (a != null && a.length > 0).

Pomysł zapewnienia krótkich testów if wydaje się dobry na powierzchni ... dopóki nie napotkasz różnic w projektach i opiniach:

  • if (0)jest traktowane jako fałsz w C, Python, JavaScript; ale traktowane jak prawda w Ruby.
  • if ([]) jest traktowane jako fałszywe w Pythonie, ale prawdziwe w JavaScript.

Każdy język ma swoje własne dobre powody, by traktować wyrażenia w taki czy inny sposób. (Na przykład jedynymi wartościami fałszowania w Ruby są, falsea nilzatem 0są prawdziwe).

Java przyjęła wyraźny projekt, aby zmusić cię do podania wartości logicznej do instrukcji if. Jeśli pospiesznie przetłumaczyłeś kod z C / Ruby / Python na Javę, nie możesz pozostawić żadnych luźnych if-testów bez zmian; musisz jawnie zapisać warunek w Javie. Zatrzymanie się na chwilę i zastanowienie się może uchronić Cię przed niechlujnymi błędami.

Nayuki
źródło
1
Czy wiesz, że x != 0to to samo co x != 0 && !isNaN(x)? Zwykle jest to s != nulldla wskaźników, ale coś innego dla wskaźników bez wskaźników.
Deduplicator
@Deduplicator w jakim języku to ten sam język?
Paŭlo Ebermann
1
Używając IEEE754, NaN ≠ 0. NaN ≠ cokolwiek. Więc jeśli (x) się wykona, a jeśli (! X) również się wykona ...
gnasher729
0

Cóż, każdy typ skalarny w C, wskaźnik, wartość logiczna (od C99), liczba (zmiennoprzecinkowa lub nie) i wyliczenie (ze względu na bezpośrednie mapowanie na liczby) ma „naturalną” wartość falsey, więc jest to wystarczające dla każdego wyrażenia warunkowego .

Java też je ma (nawet jeśli wskaźniki Java są nazywane referencjami i są mocno ograniczone), ale wprowadziło automatyczne boksowanie w Javie 5.0, które niedopuszczalnie zamazuje wody. Poza tym programiści Java podkreślają istotną wartość pisania na klawiaturze.

Jedyny błąd, który zrodził debatę czy ograniczenie wyrażenia warunkowe do logicznej typu jest literówka pisania zadanie gdzie porównano zamierzony sposób, który nie uwzględnione przez ograniczenie warunkową wyrażeń typu w ogóle , ale przez zabronienie używania nagiej przypisania wyrażania za swoją wartość.

Każdy nowoczesny kompilator C lub C ++ radzi sobie z tym łatwo, dając ostrzeżenie lub błąd w przypadku takich wątpliwych konstrukcji, jeśli zostanie o to poproszony.
W przypadkach, w których jest dokładnie to, co było zamierzone, dodanie nawiasów pomaga.

Podsumowując, ograniczenie do wartości logicznej (i odpowiednika w pudełku w Javie) wygląda na nieudaną próbę stworzenia klasy literówek spowodowaną wyborem =błędów kompilacji przypisania.

Deduplikator
źródło
Używanie ==z operandami boolowskimi, z których pierwszy jest zmienną (którą następnie można było literować =) w środku ifzdarza się znacznie rzadziej niż w przypadku innych typów, powiedziałbym, więc jest to tylko częściowo nieudana próba.
Paŭlo Ebermann
Posiadanie wartości 0.0 -> false i dowolnej wartości innej niż 0.0 -> true wcale nie wydaje mi się „naturalne”.
gnasher729
@ PaŭloEbermann: Częściowy wynik z niefortunnymi efektami ubocznymi, podczas gdy istnieje łatwy sposób na osiągnięcie celu bez skutków ubocznych, jest wyraźną porażką w mojej książce.
Deduplicator
Brakuje ci innych powodów. Co o wartości truthy z "", (Object) "", 0.0, -0.0, NaN, puste tablice, i Boolean.FALSE? Zwłaszcza ostatni jest zabawny, ponieważ jest niepustym wskaźnikiem (prawda), który rozpakowuje się na fałsz. +++ Nienawidzę także pisania if (o != null), ale oszczędzanie mi kilku znaków każdego dnia i pozwalanie mi spędzić pół dnia na debugowaniu mojego „sprytnego” wyrazu nie jest dobrym interesem. To powiedziawszy, chciałbym zobaczyć jakiś sposób na Javę: bardziej hojne zasady, ale nie pozostawiające żadnych dwuznaczności.
maaartinus
@maaartinus: Jak powiedziałem, wprowadzenie automatycznego rozpakowywania w Javie 5.0 oznaczało, że gdyby przypisali wskaźnikom wartość prawdy odpowiadającą zerowości, mieliby spory problem. Ale to jest problem z automatycznym (od-) boksem, a nie czymkolwiek innym. Język bez automatycznego (od-) boksu, taki jak C, jest na szczęście wolny od tego.
Deduplicator
-1

Moje pytanie nie dotyczy złego stylu kodowania. Wiem, że to źle, ale interesuje mnie, dlaczego C na to pozwala, a java nie.

Dwa z celów projektowych Java:

  1. Pozwól programistom skoncentrować się na problemie biznesowym. Uprość i mniej narażaj na błędy, np. Wyrzucanie elementów bezużytecznych, aby programiści nie musieli koncentrować się na wyciekach pamięci.

  2. Przenośny między platformami, np. Działa na dowolnym komputerze z dowolnym procesorem.

Używanie przypisania jako wyrażenia było znane z powodowania wielu błędów z powodu literówek, więc w celu nr 1 powyżej nie jest dozwolone sposób, w jaki próbujesz go użyć.

Ponadto wnioskowanie, że jakakolwiek niezerowa wartość = prawda i dowolna wartość zero = fałsz niekoniecznie musi być przenośna (tak, wierzcie lub nie, niektóre systemy traktują 0 jako prawdę, a 1 jako fałsz ), więc w ramach celu nr 2 powyżej nie jest domyślnie dozwolony . Oczywiście nadal możesz przesyłać treści jawnie.

John Wu
źródło
4
O ile nie został dodany w Javie 8, nie ma wyraźnego rzutowania między typami liczbowymi a wartościami logicznymi. Aby przekonwertować wartość liczbową na wartość logiczną, należy użyć operatora porównania; aby przekonwertować wartość logiczną na wartość liczbową, zwykle używa się operatora trójskładnikowego.
Peter Taylor
Możesz uzasadnić niedozwolone użycie przypisania dla jego wartości z powodu tych literówek. Ale biorąc pod uwagę, jak często widzisz == prawda i == fałsz w Javie, oczywiście ograniczenie wyrażenia kontrolnego do (opcjonalnie w ramce) typu logicznego nie pomaga tak bardzo.
Deduplicator
Java w prosty sposób zapewni przenośność wrt na „niektóre systemy traktują 0 jako prawda, a 1 jako fałsz”, ponieważ jest to zero Java i Java jest fałszem. To naprawdę nie ma znaczenia, co system operacyjny o tym myśli.
maaartinus
-1

Na przykład, co robią inne języki: Swift wymaga wyrażenia typu, który obsługuje protokół „BooleanType”, co oznacza, że ​​musi mieć metodę „boolValue”. Typ „bool” oczywiście obsługuje ten protokół i możesz tworzyć własne typy go obsługujące. Typy liczb całkowitych nie obsługują tego protokołu.

W starszych wersjach języka opcjonalne typy obsługiwały „BooleanType”, więc można było napisać „if x” zamiast „if x! = Zero”. Co sprawiło, że użycie „Opcjonalnego boolu” było bardzo mylące. Opcjonalny bool ma wartości zero, fałsz lub prawda, a „jeśli b” nie zostałby wykonany, gdyby b był zerowy, i wykonany, jeśli b był prawdziwy lub fałszywy. To nie jest już dozwolone.

I wydaje się, że jest jeden facet, który naprawdę nie lubi otwierać swoich horyzontów ...

gnasher729
źródło