Warum erlaubt Java keine numerischen Bedingungen wie if (5) {…}, wenn C dies tut?

33

Ich habe diese zwei kleinen Programme:

C

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

    return 0;
}

Java

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

die meldet die Fehlermeldung:

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

Mein Verständnis

Bisher habe ich dieses Beispiel als Demonstration der verschiedenen Typsysteme verstanden. C ist schwächer typisiert und ermöglicht die fehlerfreie Konvertierung von int nach boolean. Java ist stärker typisiert und schlägt fehl, da keine implizite Konversation zulässig ist.

Daher meine Frage: Wo habe ich Dinge falsch verstanden?

Was ich nicht suche

Meine Frage bezieht sich nicht auf einen schlechten Codierungsstil. Ich weiß, dass es schlecht ist, aber ich bin daran interessiert, warum C es zulässt und Java nicht. Aus diesem Grund interessiert mich das Typensystem der Sprache, insbesondere ihre Stärke.

toogley
quelle
22
@toogley: Was ist mit dem Typsystem in Java, das Sie speziell wissen möchten? Das Typensystem erlaubt dies nicht, da die Sprachspezifikation dies verbietet. Die Gründe, warum C dies zulässt und Java nicht alles damit zu tun hat, was in beiden Sprachen als akzeptabel angesehen wird. Das resultierende Verhalten der Typsysteme ist die Wirkung davon, nicht die Ursache.
Robert Harvey
8
@toogley: warum denkst du hast du etwas falsch verstanden? Wenn ich den Text noch einmal lese, verstehe ich Ihre Frage nicht.
Doc Brown
26
Tatsächlich ist dies kein Beispiel für eine schwache Typisierung in C. In der Vergangenheit (C89) hatte C nicht einmal einen Booleschen Typ, sodass alle "Booleschen" Operationen tatsächlich mit intWerten ausgeführt wurden. Ein besseres Beispiel wäre if (pointer).
Rufflewind
5
Ich habe abgelehnt, weil es nicht so aussieht, als wäre viel recherchiert worden, um dies zu verstehen.
jpmc26
11
Die ursprünglich gestellte Frage scheint etwas anders zu sein als die bearbeitete Version (weshalb einige der Kommentare und Antworten eine andere Frage zu beantworten scheinen). In seiner jetzigen Form scheint es hier keine Frage zu geben. Was für ein Missverständnis? Java verhält sich genau so, wie Sie es sich vorstellen.
Jamesdlin

Antworten:

134

1. C und Java sind verschiedene Sprachen

Die Tatsache, dass sie sich anders verhalten, sollte nicht schrecklich überraschen.

2. C konvertiert nicht von intnachbool

Wie könnte es C hatte bis 1999 nicht einmal einen richtigen boolTyp zum Konvertieren . C wurde in den frühen 1970er Jahren entwickelt und war Teil davon, noch bevor es C war, als es nur eine Reihe von Modifikationen an B 1 war .if

ifwar NOPfast 30 Jahre lang nicht nur in C. Es hat direkt auf numerische Werte gewirkt. Die Aussprache im C-Standard ( PDF-Link ) gibt auch über ein Jahrzehnt nach Einführung von bools in C das Verhalten von if(S. 148) und ?:(S. 100) mit den Begriffen "ungleich 0" und "gleich 0" an "und nicht die booleschen Ausdrücke" wahr "oder" falsch "oder ähnliches.

Günstig, ...

3. ... Zahlen entsprechen einfach den Anweisungen des Prozessors.

JZund JNZsind Ihre grundlegenden x86-Assemblyanweisungen für bedingte Verzweigungen. Die Abkürzungen sind " J ump wenn Z ero" und " J ump wenn N ot Z ero". Die Äquivalente für den PDP-11, aus dem C stammt, sind BEQ(" B- Ranch, wenn EQ ual") und BNE(" B- Ranch, wenn N ot E qual").

Diese Anweisungen prüfen, ob die vorherige Operation zu einer Null geführt hat oder nicht, und springen (oder nicht) entsprechend.

4. Java legt viel mehr Wert auf Sicherheit als C jemals zuvor 2

Aus Sicherheitsgründen haben sie entschieden, dass die Beschränkung ifauf booleans die Kosten wert ist (sowohl für die Implementierung einer solchen Beschränkung als auch für die daraus resultierenden Opportunitätskosten).


1. B hat überhaupt keine Typen. Assemblersprachen tun dies im Allgemeinen auch nicht. B- und Assemblersprachen schaffen es jedoch, Verzweigungen problemlos zu verarbeiten.

2. Mit den Worten von Dennis Ritchie bei der Beschreibung der geplanten Änderungen an B, die zu C wurden (Betonung meiner):

... schien ein Typisierungsschema notwendig zu sein, um mit Zeichen und Byteadressen umzugehen und sich auf die kommende Gleitkomma-Hardware vorzubereiten. Andere Themen, insbesondere die Typensicherheit und die Schnittstellenprüfung, schienen damals nicht so wichtig zu sein, wie sie später wurden.

8bittree
quelle
13
Netter Punkt zu Booleschen Ausdrücken in C, die direkt auf Prozessoranweisungen abgebildet werden. Ich hatte vorher nicht darüber nachgedacht.
Robert Harvey
17
Ich denke Punkt 4 ist irreführend, da er zu implizieren scheint, dass C einen gewissen Sicherheitsfokus hat ... C lässt Sie im Grunde alles tun, was Sie wollen: C geht davon aus, dass Sie wissen, was Sie tun, oft zu spektakulär katastrophalen Ergebnissen.
TemporalWolf
13
@TemporalWolf Du sagst, als ob es schlecht wäre, dich tun zu lassen, was du willst. Der Unterschied meiner Meinung nach ist, dass C für Programmierer geschrieben wurde und eine Grundkompetenz erwartet wird. Java ist für Code-Affen geschrieben und wenn Sie tippen können, können Sie es programmieren. Oft spektakulär schlecht, aber wen interessiert das schon? Ich werde nie vergessen, wann ein Lehrer in der Java-Einführungsklasse, die ich als Teil meines CS-Moll nehmen musste, darauf hingewiesen hat, dass die Verwendung von Rekursion zur Berechnung der Fibonnaci-Zahlen nützlich sein könnte, weil es "einfach zu schreiben" sei. Deshalb haben wir die Software, die wir haben.
DRF
25
@DRF Einer meiner Professoren für eine C-Networking-Klasse sagte: "C ist wie eine Schachtel Handgranaten, bei der alle Stifte herausgezogen sind." Du hast eine Menge Power, aber es ist im Grunde garantiert, dass es in die Luft jagt. In den allermeisten Fällen lohnt sich der Aufwand nicht und Sie sind mit einer höheren Sprache weitaus produktiver. Habe ich Python in hackiges C-Bit-Twiddling umgewandelt, um eine Geschwindigkeitssteigerung von 6 Größenordnungen zu erzielen? Ja, ja ich habe. Das ist aber die Ausnahme, nicht die Regel. Ich kann an einem Tag in Python das schaffen, was in C zwei Wochen dauern würde ... und ich bin ein anständiger C-Programmierer.
TemporalWolf
11
@DRF Angesichts der Verbreitung von Pufferüberlauf-Exploits in Mainstream-Software, die von namhaften Unternehmen entwickelt wurde, kann man anscheinend auch Programmierern mit Grundkompetenz nicht trauen, nicht von den Beinen zu schießen.
Setzen Sie Monica
14

C 2011 Online-Entwurf

6.8.4.1 Die ifAnweisung

Einschränkungen

1 Die Steuerung Ausdruck einer ifErklärung wird skalaren Typ.

Semantik

2 In beiden Formen wird die erste Unterstatement ausgeführt, wenn der Ausdruck ungleich 0 ist. In der elseForm wird die zweite Unterstatement ausgeführt, wenn der Ausdruck gleich 0 ist. Wenn die erste Unterstatement über eine Beschriftung erreicht wird, ist die zweite Unterstatement nicht ausgeführt.

3 elseWenn die Syntax dies zulässt, wird An mit dem lexikalisch nächstgelegenen Vorgänger verknüpft.

Beachten Sie, dass diese Klausel nur angibt, dass der steuernde Ausdruck einen skalaren Typ ( char/ short/ int/ long/ etc.) Haben soll , nicht speziell einen booleschen Typ. Eine Verzweigung wird ausgeführt, wenn der steuernde Ausdruck einen Wert ungleich Null hat.

Vergleichen Sie das mit

Java SE 8-Sprachspezifikation

14.9 Die ifAnweisung

Die ifAnweisung ermöglicht die bedingte Ausführung einer Anweisung oder die bedingte Auswahl von zwei Anweisungen, wobei die eine oder die andere, jedoch nicht beide ausgeführt werden.
    IfThenStatement :
        if ( Ausdruck ) Anweisung

    IfThenElseStatement :
        if ( Ausdruck ) StatementNoShortIf else- Anweisung

    IfThenElseStatementNoShortIf :
        if ( Ausdruck ) StatementNoShortIf else StatementNoShortIf
Der Ausdruck muss vom Typ booleanoder sein Boolean. Andernfalls tritt ein Fehler beim Kompilieren auf.

In Java (OTOH) muss der steuernde Ausdruck in einer ifAnweisung einen Booleschen Typ haben.

Es geht also nicht um schwache oder starke Typisierung, sondern darum, was die jeweilige Sprachdefinition als gültigen Kontrollausdruck angibt.

Bearbeiten

In Bezug auf die Gründe, warum die Sprachen in dieser Hinsicht unterschiedlich sind, gibt es mehrere Punkte:

  1. C wurde von B abgeleitet, was eine "typenlose" Sprache war - im Grunde war alles ein 32- bis 36-Bit-Wort (abhängig von der Hardware), und alle arithmetischen Operationen waren Ganzzahloperationen. Das Typensystem von C wurde ein wenig nach dem anderen angeschraubt, so dass ...

  2. C hatte bis zur 1999er Version der Sprache keinen bestimmten Booleschen Typ. C folgte einfach der B-Konvention, Null für die Darstellung falseund Nicht-Null für die Darstellung zu verwenden true.

  3. Java datiert C um ein paar Jahrzehnte nach und wurde speziell entwickelt, um einige der Mängel von C und C ++ zu beheben. Dazu gehörte zweifellos die Verschärfung der Einschränkung, was ein Kontrollausdruck in einer ifAnweisung sein könnte.

  4. Es gibt keinen Grund zu der Annahme, dass zwei Programmiersprachen die gleichen Schritte ausführen. Sogar Sprachen, die eng mit C und C ++ verwandt sind, weichen auf interessante Weise voneinander ab, so dass Sie legale C-Programme haben können, die keine legalen C ++ - Programme sind oder legale C ++ - Programme, aber mit unterschiedlicher Semantik usw.

John Bode
quelle
Zu traurig, ich kann nicht zwei Antworten als "akzeptiert" markieren ..
Googley
1
Ja, das ist eine gute Wiederholung der Frage. Aber die Frage war, warum es diesen Unterschied zwischen den beiden Sprachen gibt. Sie haben das überhaupt nicht angesprochen.
Dawood sagt, Monica
@DawoodibnKareem: Die Frage war, warum C die Konvertierung von intnach zuließ , booleanwährend Java dies nicht zuließ . Die Antwort ist, dass es in C keine solche Konvertierung gibt. Die Sprachen sind unterschiedlich, weil sie verschiedene Sprachen sind.
John Bode
Ja, "es geht nicht um schwaches oder starkes Tippen". Betrachten Sie einfach Auto-Boxing und Auto-Unboxing. Wenn C diese hätte, könnte es auch keinen skalaren Typ zulassen.
Deduplikator
5

Viele der Antworten scheinen auf den eingebetteten Zuweisungsausdruck abzuzielen, der sich im bedingten Ausdruck befindet. (Dies ist zwar eine bekannte Art von potenzieller Gefahr, in diesem Fall ist es jedoch nicht die Quelle der Java-Fehlermeldung.)

Möglicherweise liegt dies daran, dass das OP die eigentliche Fehlermeldung nicht veröffentlicht hat und das ^Caret direkt auf den =des Zuweisungsoperators verweist .

Der Compiler zeigt jedoch auf, =weil der Operator den endgültigen Wert (und damit den endgültigen Typ) des Ausdrucks erzeugt, den die Bedingung sieht.

Es beschwert sich über das Testen eines nicht-booleschen Werts mit der folgenden Art von Fehler:

Fehler: Inkompatible Typen: int kann nicht in Boolean konvertiert werden

Das Testen von Ganzzahlen ist zwar manchmal praktisch, wird jedoch als potenzielle Gefahr angesehen, die von den Java-Designern vermieden wird. Immerhin hat Java einen echten Booleschen Datentyp , der von C nicht unterstützt wird (es gibt keinen Booleschen Typ) .

Dies gilt auch für die Testzeiger von C für null / non-null via if (p) ...und if (!p) ..., die Java ebenfalls nicht zulässt, stattdessen einen expliziten Vergleichsoperator zu erfordern, um den erforderlichen Booleschen Wert zu erhalten.

Erik Eidt
quelle
1
C hat einen Booleschen Typ. Aber das ist neuer als die ifAussage.
MSalters
3
@MSalters Cs Bool ist immer noch eine ganze Zahl unter dem Deckmantel, daher können Sie dies tun bool b = ...; int v = 5 + b;. Dies unterscheidet sich von Sprachen mit einem vollständigen Booleschen Typ, der in der Arithmetik nicht verwendet werden kann.
Jules
Der Boolesche Wert von C ist nur eine sehr kleine Ganzzahl. "wahr" und "falsch" können leicht mit Makros oder was auch immer definiert werden.
Oskar Skog
4
@Jules: Sie weisen nur darauf hin, dass C eine schwache Typensicherheit aufweist. Nur weil ein boolescher Typ in einen ganzzahligen Wert konvertiert wird , bedeutet dies nicht, dass es sich um einen ganzzahligen Typ handelt. Nach Ihrer Logik sind Integer-Typen Gleitkommatypen, da dies int v = 5; float f = 2.0 + v;in C
zulässig
1
@MSalters ist tatsächlich _Booleiner der vom Standard definierten vorzeichenlosen Integer- Standardtypen (siehe 6.2.5 / 6).
Ruslan
2

inkompatible Typen: int kann nicht in boolean konvertiert werden

Ich bin daran interessiert, warum C es zulässt und Java nicht. Aus diesem Grund interessiert mich das Typensystem der Sprache, insbesondere ihre Stärke.

Ihre Frage besteht aus zwei Teilen:

Warum konvertiert Java nicht intnach boolean?

Dies läuft darauf hinaus, dass Java so explizit wie möglich sein soll. Es ist sehr statisch, sehr "in deinem Gesicht" mit seinem Typensystem. Dinge, die automatisch in andere Sprachen geschrieben werden, sind in Java nicht so. Du musst auch schreiben int a=(int)0.5. Die Konvertierung floatin intwürde Informationen verlieren. das gleiche wie konvertieren intzu booleanund wäre daher fehleranfällig. Außerdem hätten sie viele Kombinationen angeben müssen. Sicher, diese Dinge scheinen offensichtlich zu sein, aber sie wollten sich auf der Seite der Vorsicht irren.

Im Vergleich zu anderen Sprachen war Java in seiner Spezifikation äußerst genau, da der Bytecode nicht nur ein internes Implementierungsdetail war. Sie müssten alle Wechselwirkungen genau spezifizieren. Riesiges Unterfangen.

Warum ifakzeptiert nicht andere Typen als boolean?

ifkönnte durchaus definiert werden, um andere Typen als zuzulassen boolean. Es könnte eine Definition haben, die besagt, dass Folgendes äquivalent ist:

  • true
  • int != 0
  • String mit .length>0
  • Jeder andere Objektverweis, der nicht null(und kein Booleanwith-Wert false) ist.
  • Oder sogar: jede andere Objektreferenz, die nicht existiert nullund deren Methode Object.check_if(von mir nur für diesen Anlass erfunden) zurückgibt true.

Sie taten nicht; Es gab keine wirkliche Notwendigkeit, und sie wollten es so robust, statisch, transparent, einfach zu lesen usw. wie möglich haben. Keine impliziten Funktionen. Außerdem wäre die Implementierung ziemlich komplex, da ich sicher bin, dass jeder Wert auf alle möglichen Fälle getestet werden muss, sodass die Leistung möglicherweise auch einen kleinen Einfluss hat (Java war auf den Computern dieses Tages früher nur langsam; denken Sie daran) Bei den ersten Releases gab es keine JIT-Compiler, zumindest nicht auf den damals verwendeten Computern.

Tieferer Grund

Ein tieferer Grund könnte wohl die Tatsache sein, dass Java seine primitiven Typen hat, weshalb sein Typensystem zwischen Objekten und Primitiven hin und her gerissen ist. Wenn sie diese vermieden hätten, wäre es vielleicht anders gekommen. Mit den im vorherigen Abschnitt angegebenen Regeln müssten sie die Wahrhaftigkeit jedes einzelnen Primitivs explizit definieren (da die Primitive keine Superklasse teilen und es nullfür Primitive keine genaue Definition gibt ). Dies würde sich schnell in einen Albtraum verwandeln.

Ausblick

Nun, und am Ende ist es vielleicht nur eine Präferenz der Sprachdesigner. Jede Sprache scheint ihren eigenen Weg dorthin zu finden ...

Zum Beispiel hat Ruby keine primitiven Typen. Alles, buchstäblich alles, ist ein Objekt. Sie haben es sehr leicht, dafür zu sorgen, dass jedes Objekt eine bestimmte Methode hat.

Ruby sucht nach Wahrhaftigkeit für alle Arten von Objekten, die Sie darauf werfen können. Interessanterweise hat es immer noch keinen booleanTyp (weil es keine Primitive hat) und es hat auch keine BooleanKlasse. Wenn Sie fragen, mit welcher Klasse der Wert true(handlich verfügbar true.class) ist, erhalten Sie TrueClass. Diese Klasse hat tatsächlich Methoden, nämlich die 4 Operatoren für boolean ( | & ^ ==). Hier ifhält seinen Wert Falsey , wenn und nur wenn es entweder falseoder nil(die nullvon Ruby). Alles andere ist wahr. Also, 0oder ""sind beide wahr.

Es wäre für sie trivial gewesen, eine Methode Object#truthy?zu entwickeln, die für jede Klasse implementiert werden kann und eine individuelle Wahrhaftigkeit zurückgibt. Beispielsweise String#truthy?könnte implementiert worden sein, um für nicht leere Zeichenfolgen oder so weiter wahr zu sein. Sie taten es nicht, obwohl Ruby in den meisten Abteilungen das Gegenteil von Java ist (dynamisches Duck-Typing mit Mixin, Wiedereröffnung von Klassen und so weiter).

Was für einen Perl-Programmierer, der es gewohnt $value <> 0 || length($value)>0 || defined($value)ist, die Wahrheit zu sein , vielleicht überraschend ist . Und so weiter.

Geben Sie SQL mit der Konvention ein, dass nullein Ausdruck in jedem Ausdruck automatisch falsch ist, egal was passiert. Also (null==null) = false. In Ruby (nil==nil) = true. Glückliche Zeiten.

AnoE
quelle
Eigentlich ((int)3) * ((float)2.5)ist es in Java ziemlich gut definiert (es ist 7.5f).
Paŭlo Ebermann
Du hast recht, @ PaŭloEbermann, ich habe dieses Beispiel gelöscht.
AnoE
Woah da ... würde mich über Kommentare der Downvoter und derjenigen freuen, die dafür gestimmt haben, die Antwort tatsächlich zu löschen.
AnoE
Tatsächlich verliert die Konvertierung von intnach floatauch Informationen im Allgemeinen. Verbietet Java auch solche impliziten Besetzungen?
Ruslan
@Ruslan nein (das gleiche gilt für long → double) - Ich denke, dass der potenzielle Informationsverlust nur an den am wenigsten signifikanten Stellen auftritt und nur in Fällen auftritt, die als nicht so wichtig erachtet werden (ziemlich große Ganzzahlwerte).
Paŭlo Ebermann
1

Zusätzlich zu den anderen guten Antworten möchte ich über die Konsistenz zwischen den Sprachen sprechen.

Wenn wir an eine mathematisch reine if-Anweisung denken, verstehen wir, dass die Bedingung entweder wahr oder falsch sein kann, kein anderer Wert. Jede wichtige Programmiersprache respektiert dieses mathematische Ideal. Wenn Sie einer if-Anweisung einen booleschen true / false-Wert zuweisen, können Sie davon ausgehen, dass Sie stets ein konsistentes, intuitives Verhalten feststellen.

So weit, ist es gut. Dies ist, was Java implementiert, und nur was Java implementiert.

Andere Sprachen versuchen, Bequemlichkeiten für nicht-boolesche Werte zu bringen. Beispielsweise:

  • Angenommen, es nist eine ganze Zahl. Definieren Sie if (n)nun als Abkürzung für if (n != 0).
  • Angenommen, es xhandelt sich um eine Gleitkommazahl. Definieren Sie if (x)nun als Abkürzung für if (x != 0 && !isNaN(x)).
  • Angenommen, es phandelt sich um einen Zeigertyp. Definieren Sie if (p)nun als Abkürzung für if (p != null).
  • Angenommen, es shandelt sich um einen Zeichenfolgentyp. Jetzt definieren if (s), um zu sein if (s != null && s != "").
  • Angenommen, es ahandelt sich um einen Array-Typ. Jetzt definieren if (a), um zu sein if (a != null && a.length > 0).

Diese Idee, Kurzformulierungen für If-Tests bereitzustellen, scheint an der Oberfläche gut zu sein ... bis Sie auf Unterschiede in den Designs und Meinungen stoßen:

  • if (0)wird in C, Python, JavaScript als falsch behandelt; aber in Ruby als wahr behandelt.
  • if ([]) wird in Python als false behandelt, in JavaScript jedoch als true.

Jede Sprache hat ihre eigenen guten Gründe, um Ausdrücke auf die eine oder andere Weise zu behandeln. (Zum Beispiel sind die einzigen falschen Werte in Ruby falseund nildaher 0ist wahr.)

Java hat ein explizites Design eingeführt, um Sie zu zwingen, einer if-Anweisung einen Booleschen Wert zuzuweisen. Wenn Sie hastig Code von C / Ruby / Python nach Java übersetzt haben, können Sie keine laxen if-Tests unverändert lassen. Sie müssen die Bedingung explizit in Java ausschreiben. Nehmen Sie sich einen Moment Zeit zum Innehalten und überlegen Sie, wie Sie schlampige Fehler vermeiden können.

Nayuki
quelle
1
Weißt du das x != 0ist das selbe wie x != 0 && !isNaN(x)? Es ist normalerweise auch s != nullfür Zeiger, aber etwas anderes für Nicht-Zeiger.
Deduplizierer
@Deduplicator In welcher Sprache ist das gleich?
Paŭlo Ebermann
1
Bei Verwendung von IEEE754 ist NaN ≤ 0. NaN ≤ alles. Also, wenn (x) ausgeführt würde, und wenn (! X) auch ausgeführt würde ...
gnasher729
0

Nun, jeder skalare Typ in C, Pointer, Boolean (seit C99), Number (Gleitkomma oder nicht) und Enumeration (aufgrund der direkten Zuordnung zu Zahlen) hat einen "natürlichen" Falsey-Wert, das ist also gut genug für jeden bedingten Ausdruck .

Java hat diese ebenfalls (auch wenn Java-Zeiger als Referenzen bezeichnet werden und stark eingeschränkt sind), hat jedoch Auto-Boxing in Java 5.0 eingeführt, das die Gewässer inakzeptabel durcheinander bringt. Java-Programmierer weisen auch darauf hin, wie wichtig es ist, mehr zu tippen.

Der einzige Fehler, der die Debatte darüber ausgelöst hat, ob bedingte Ausdrücke auf den Booleschen Typ beschränkt werden sollen, ist der Tippfehler, eine Zuweisung zu schreiben, bei der ein Vergleich angestrebt wurde. Dies wird nicht dadurch behoben, dass der Typ der bedingten Ausdrücke überhaupt eingeschränkt wird , sondern die Verwendung eines nackten Zuweisungsausdrucks untersagt wird für seinen Wert.

Jeder moderne C- oder C ++ - Compiler handhabt dies problemlos und gibt bei Fragen eine Warnung oder einen Fehler für solche fragwürdigen Konstrukte aus.
In den Fällen, in denen genau das beabsichtigt ist, hilft das Hinzufügen von Klammern.

Zusammenfassend lässt sich sagen, dass das Beschränken auf Boolesche Werte (und das in Java in Kästchen gesetzte Äquivalent) ein Fehlversuch ist, eine Klasse von Tippfehlern zu =erstellen, die durch die Auswahl von Zuweisungskompilierungsfehlern verursacht werden.

Deduplizierer
quelle
Die Verwendung ==von booleschen Operanden, von denen der erste eine Variable ist (auf die dann getippt werden könnte =), in einem ifpassiert viel seltener als bei anderen Typen, würde ich sagen, es ist also nur ein halb fehlgeschlagener Versuch.
Paŭlo Ebermann
0.0 -> false und einen anderen Wert als 0.0 -> true zu haben, sieht für mich überhaupt nicht "natürlich" aus.
gnasher729
@ PaŭloEbermann: Teilergebnis mit unglücklichen Nebenwirkungen, während es einen einfachen Weg gibt, das Ziel ohne Nebenwirkungen zu erreichen, ist ein klares Versagen in meinem Buch.
Deduplikator
Sie vermissen die anderen Gründe. Was ist mit dem truthy Wert "", (Object) "", 0.0, -0.0, NaN, leere Arrays, und Boolean.FALSE? Besonders das letzte ist lustig, da es sich um einen Nicht-Null-Zeiger (true) handelt, der von false abweicht. +++ Ich hasse es auch zu schreiben if (o != null), aber es ist kein gutes Geschäft, mir jeden Tag ein paar Zeichen zu ersparen und mir einen halben Tag Zeit zu lassen, um meinen "cleveren" Ausdruck zu debuggen. Das heißt, ich würde gerne einen Mittelweg für Java sehen: großzügigere Regeln, aber überhaupt keine Mehrdeutigkeit.
Maaartinus
@maaartinus: Wie gesagt, die Einführung von Auto-Unboxing in Java 5.0 bedeutete, dass sie ein ziemliches Problem hätten, wenn sie einen Wahrheitswert zugewiesen hätten, der der Nichtigkeit von Zeigern entsprach. Aber das ist ein Problem mit Auto- (Un-) Boxen, sonst nichts. Eine Sprache ohne Auto- (Un-) Boxing wie C ist glücklicherweise frei davon.
Deduplikator
-1

Meine Frage bezieht sich nicht auf einen schlechten Codierungsstil. Ich weiß, dass es schlecht ist, aber ich bin interessiert daran, warum C es zulässt und Java nicht.

Zwei der Entwurfsziele von Java waren:

  1. Ermöglichen Sie dem Entwickler, sich auf das Geschäftsproblem zu konzentrieren. Machen Sie Dinge einfacher und weniger fehleranfällig, z. B. Garbage Collection, damit Entwickler sich nicht auf Speicherverluste konzentrieren müssen.

  2. Portabel zwischen Plattformen, zB lauffähig auf jedem Computer mit jeder CPU.

Es war bekannt, dass die Verwendung von Zuordnung als Ausdruck aufgrund von Tippfehlern viele Fehler verursacht. Daher ist es unter Ziel 1 oben nicht zulässig, wie Sie es verwenden möchten.

Daraus zu schließen, dass ein Wert ungleich Null = wahr und ein Wert null = falsch nicht notwendigerweise portabel ist (ja, ob Sie es glauben oder nicht, manche Systeme behandeln 0 als wahr und 1 als falsch ), ist also unter Ziel 2 oben implizit nicht zulässig . Du kannst natürlich trotzdem explizit besetzen.

John Wu
quelle
4
Sofern es nicht in Java 8 hinzugefügt wurde, gibt es keine explizite Umwandlung zwischen numerischen Typen und Booleschen Werten. Um einen numerischen Wert in einen Booleschen Wert umzuwandeln, müssen Sie einen Vergleichsoperator verwenden. Um einen Booleschen Wert in einen numerischen Wert umzuwandeln, verwenden Sie normalerweise den ternären Operator.
Peter Taylor
Sie können die Verwendung einer Zuweisung für ihren Wert aufgrund dieser Tippfehler ablehnen. Aber wenn man bedenkt, wie oft man in Java == true und == false sieht, hilft es natürlich nicht viel, den steuernden Ausdruck auf (optional mit einem Kästchen versehene) boolesche Typen zu beschränken.
Deduplikator
Java würde trivial die Portabilität sicherstellen, wenn "einige Systeme 0 als wahr und 1 als falsch behandeln", da es sich um Java-Null und Java-Falsch handelt. Es ist wirklich egal, was das Betriebssystem darüber denkt.
Maaartinus
-1

Zum Beispiel, was andere Sprachen tun: Swift benötigt einen Ausdruck eines Typs, der das "BooleanType" -Protokoll unterstützt, was bedeutet, dass er eine "boolValue" -Methode haben muss. Der Typ "bool" unterstützt dieses Protokoll offensichtlich und Sie können Ihre eigenen Typen erstellen, die es unterstützen. Ganzzahltypen unterstützen dieses Protokoll nicht.

In älteren Versionen der Sprache unterstützten optionale Typen "BooleanType", sodass Sie "if x" anstelle von "if x! = Nil" schreiben konnten. Was die Verwendung eines "optionalen Bool" sehr verwirrend machte. Ein optionaler Bool hat die Werte null, falsch oder wahr und "wenn b" würde nicht ausgeführt, wenn b null wäre und ausgeführt, wenn b wahr oder falsch wäre. Dies ist nicht mehr erlaubt.

Und es scheint einen Typ zu geben, der es nicht mag, seinen Horizont zu öffnen ...

gnasher729
quelle