Null als Konstante?

15

Ich bin kürzlich auf diese Programmiersprache gestoßen:

const float Zero = 0.0;

Das wird dann in Vergleichen verwendet:

if (x > Zero) {..}

Kann mir jemand erklären, ob dies wirklich effizienter, lesbarer oder wartbarer ist als:

if (x > 0.0) {..}

HINWEIS: Ich kann mir andere Gründe vorstellen , um diese Konstante zu definieren. Ich frage mich nur, wie sie in diesem Zusammenhang verwendet wird.

NWS
quelle
31
Die Entwickler planen, den Code auf ein Universum zu portieren, in dem die Gesetze der Mathematik unterschiedlich sind?
Vaughandroid
6
Im Ernst, ich kann mir keinen einzigen guten Grund dafür vorstellen. Die einzigen Erklärungen, die ich finden kann, sind übereifrige Codierungsstandards oder einige Entwickler, die "magische Zahlen sind schlecht" gehört haben, aber nicht verstehen, warum (oder was eine magische Zahl
ausmachen
@Baqueta -Ein alternatives Universum? Ich denke, sie haben schon dort gelebt! Was magische Zahlen angeht, stimme ich zu, jedoch verwende ich die Faustregel, dass Alles außer 0 & 1 konstant gemacht werden sollte.
NWS
1
Wenn xtype vorhanden ist float, wird die x > 0.0Beförderung zu erzwungen double, was möglicherweise weniger effizient ist. Das ist kein guter Grund für eine benannte Konstante verwendet allerdings nur für dafür , dass Ihre Konstanten den richtigen Typ haben (zB 0f, float(0)oder decltype(x)(0)).
Mike Seymour
1
@JoSo: um fair zu sein, ist die Art von 13.37nicht float, es ist double. Also , wenn Sie will floatdann war es denkbar Ihr Tutor richtig. In einigen Kontexten (z. B. Zuweisung zu einem Float) 13.37wird implizit in den von floatIhnen gewünschten konvertiert , in anderen Kontexten (z. B. Abzug von Vorlagentypen) wird dies nicht der Fall sein, während der Datentyp static const floatimmer wie von Ihnen beabsichtigt beginnt. Daher typsicherer. Wohlgemerkt, wäre es auch so 13.37f! Es gibt jedoch noch andere Gründe, das Makro zu vermeiden, als "Typensicherheit". Es ist also genauso wahrscheinlich, dass der Tutor Ihnen ein schlechtes Argument geliefert hat.
Steve Jessop

Antworten:

29

Mögliche Gründe sind das Zwischenspeichern, Benennen oder Erzwingen des Typs

Caching (nicht zutreffend)

Sie möchten die Kosten für das Erstellen eines Objekts während des Vergleichs vermeiden. In Java wäre ein Beispiel

BigDecimal zero = new BigDecimal ("0.0");

Dies ist ein ziemlich schwerer Erstellungsprozess und wird mit der bereitgestellten statischen Methode besser bedient:

BigDecimal zero = BigDecimal.ZERO;

Auf diese Weise können Vergleiche durchgeführt werden, ohne dass sich die Erstellungskosten wiederholen, da das BigDecimal während der Initialisierung von der JVM vorab zwischengespeichert wird.

Bei dem, was Sie beschrieben haben, führt ein Grundelement denselben Job aus. Dies ist in Bezug auf Caching und Leistung weitgehend überflüssig.

Benennung (unwahrscheinlich)

Der ursprüngliche Entwickler versucht, eine systemweit einheitliche Namenskonvention für gemeinsame Werte bereitzustellen. Dies hat einige Vorzüge, insbesondere bei ungewöhnlichen Werten, aber etwas so grundlegendes wie Null ist es nur im Fall des früheren Caching-Falls wert.

Erzwingender Typ (höchstwahrscheinlich)

Der ursprüngliche Entwickler versucht, einen bestimmten primitiven Typ zu erzwingen, um sicherzustellen, dass Vergleiche auf den richtigen Typ und möglicherweise auf einen bestimmten Maßstab (Anzahl der Dezimalstellen) übertragen werden. Dies ist in Ordnung, aber der einfache Name "Null" ist wahrscheinlich nicht ausreichend detailliert für diesen Anwendungsfall, da ZERO_1DP ein geeigneterer Ausdruck der Absicht ist.

Gary Rowe
quelle
2
+1 für das Erzwingen des Typs. Ich füge hinzu, dass in Sprachen wie C ++, die das Überladen von Operatoren ermöglichen, das Definieren einer Konstanten und das Verwenden typedefvon den Variablen den Typ an genau einer Stelle behalten und das Ändern ermöglichen, ohne den Code ändern zu müssen.
Blrfl
3
Das Erzwingen von Typ ist höchstwahrscheinlich nicht das, wonach sie gesucht haben. Dies ist jedoch die beste Erklärung dafür, warum dies möglich ist!
NWS
7
Zum Erzwingen von Typ würde ich wahrscheinlich eher einfach verwenden 0.0f.
Svish
In vb.net kann es manchmal nützlich sein, den Typ zu erzwingen, wenn bitweise Operatoren für Bytes ein Byte-Ergebnis liefern. Sprichwort byteVar1 = byteVar2 Or CB128scheint ein wenig netter als byteVar1 = byteVar2 Or CByte(128). Natürlich wäre es noch besser, ein richtiges numerisches Suffix für Bytes zu haben. Da C # die Operanden von bitweisen zu Operatoren befördert, intselbst wenn das Ergebnis garantiert in ein passt byte, ist das Problem dort nicht so relevant.
Supercat
Ich bin nicht sicher, ob der konstante Name Null für '0' ist, aber manchmal hilft dies bei der Lesbarkeit des Codes. Wenn Sie zum Beispiel diese Konstante für Null haben - "ROOT_TYPE_ID = 0" -, können Sie eine Anweisung wie if (id! = ROOT_TYPE_ID) {..}
Tech Junkie
6

Es ist wegen "Tooling Nagging"

Ein möglicher Grund, warum ich hier nicht aufgeführt sehe, ist, dass viele Qualitätswerkzeuge die Verwendung von magischen Zahlen kennzeichnen . Es ist oft eine schlechte Praxis, magische Zahlen in einen Algorithmus zu werfen, ohne sie für spätere Änderungen deutlich sichtbar zu machen, insbesondere wenn sie an mehreren Stellen im Code dupliziert werden.

Diese Tools kennzeichnen solche Probleme zwar zu Recht, führen jedoch häufig zu Fehlalarmen in Situationen, in denen diese Werte harmlos sind und höchstwahrscheinlich statisch oder nur Initialisierungswerte sind.

Und wenn das passiert, haben Sie manchmal die Wahl zwischen:

  • Markieren Sie sie als falsch-positiv, wenn das Tool dies zulässt (normalerweise mit einem speziell formatierten Kommentar, was für Benutzer, die das Tool NICHT verwenden, ärgerlich ist).
  • oder diese Werte in Konstanten zu extrahieren, ob es darauf ankommt oder nicht.

Über Leistung

Es hängt von der Sprache ab, die ich vermute, aber dies ist in Java ziemlich häufig und hat keine Auswirkungen auf die Leistung, da die Werte zur Kompilierungszeit inline sind, wenn es sich um echte Konstanten handelt static final. In C oder C ++ hätte dies keine Auswirkungen, wenn sie entweder als Konstanten oder sogar als Pre-Prozessor-Makros deklariert würden.

Haylem
quelle
5

Dies kann sinnvoll sein, da explizit definiert wird Zero, dass es sich um einen Typ handelt float.

Zumindest in C und C ++ ist der Wert 0.0vom Typ double, während das Äquivalent floatist 0.0f. Es xist also immer ein floatSprichwort, vorausgesetzt, man vergleicht mit

x > 0.0

während tatsächlich zu fördern x, doubleum die Art, 0.0die zu Problemen führen könnte (mit Gleichheitstests vor allem) zu entsprechen. Der Vergleich ohne Umrechnung wäre natürlich

x > 0.0f

was dasselbe macht wie

float Zero = 0.0; // double 0.0 converted to float  
x > Zero

Trotzdem halte ich es für viel nützlicher, Warnungen vor Konvertierungen im Compiler zu aktivieren, anstatt dass Benutzer umständlichen Code schreiben.

Benjamin Bannier
quelle
1

Zunächst wird hier Null definiert als float, nicht int. Dies hat natürlich keine Auswirkung auf den Vergleich. In anderen Fällen kann es jedoch zu Unterschieden kommen, wenn diese Konstante verwendet wird.

Ich sehe keinen anderen Grund, warum Zerohier eine Konstante deklariert wird. Es ist nur ein Codierungsstil, und es ist besser, dem Stil zu folgen, wenn er überall in diesem bestimmten Programm verwendet wird.

superM
quelle
1

Es ist mit ziemlicher Sicherheit während der Ausführung genauso effizient (es sei denn, Ihr Compiler ist sehr primitiv) und während der Kompilierung etwas weniger effizient.

Was die Frage betrifft, ob das lesbarer ist als x > 0... Denken Sie daran, dass es Menschen gibt, die COBOL ehrlich und aufrichtig für eine großartige Idee und eine Freude bei der Arbeit halten es gibt sogar einige Programmierer mit der gleichen Meinung über C ++!) Mit anderen Worten, Sie werden sich in diesem Punkt nicht einig werden, und es lohnt sich wahrscheinlich nicht, darüber zu streiten.

Kilian Foth
quelle
0

[ist] das ist wirklich effizienter oder lesbarer oder wartbarer als:

if (x > 0.0) {..}

Wenn Sie generischen (dh nicht typspezifischen) Code geschrieben haben, dann sehr wahrscheinlich. Eine zero()Funktion kann für jeden algebraischen Typ oder für jeden Typ gelten, bei dem es sich um eine Gruppenaddition handelt. Es könnte eine ganze Zahl sein, es könnte ein Gleitkommawert sein, es könnte sogar eine Funktion sein, wenn Ihre Variable beispielsweise selbst eine Funktion innerhalb eines linearen Raums ist (z. B. ist x eine lineare Funktion der Form z -> a_x * z + b_x) und zero()liefert dann die Funktion, wobei a und b beide zero()vom zugrunde liegenden Typ sind.

Man würde also einen solchen Code beispielsweise in C ++ (obwohl ein zero()AFAIK nicht sehr verbreitet ist) oder in Julia und vielleicht in anderen Sprachen erwarten .

einpoklum
quelle