if und UND-verknüpfte Bedignungen

Gast #4770401
Hallo zusammen!

Was ist denn besser? Eine Latte von UND-verknüpften Bedingungen -die 
auch Rückgabewerte von Funktionsaufrufen beinhalten-, in einer 
if-Abfrage und lieber ineinander mit aufsteigender Komplexität 
verschachtelt, um Rechenzeit zu sparen?

Danke & Grüße
Blub
Kannst Du ruhig hintereinander schreiben. Da von links nach rechts 
abgearbeitet wird, und bei dem ersten false eh abgebrochen wird.
Um Rechenzeit zu sparen am besten die Bedingungen die am 
häufigsten/schnellsten false liefern ganz nach links schreiben.
Gast
Richtig, beides ist (zumindest in C und einigen anderen Sprachen) 
äquivalent. Immer daryn denken falls eine der aufgerufenen Funktionen 
gewünschte Seiteneffekte hat.
Gast
Stefan P. schrieb:
> Kannst Du ruhig hintereinander schreiben. Da von links nach rechts
> abgearbeitet wird, und bei dem ersten false eh abgebrochen wird.
> Um Rechenzeit zu sparen am besten die Bedingungen die am
> häufigsten/schnellsten false liefern ganz nach links schreiben.

Super! Danke! Die Antwort, die ich gebraucht und erhofft habe! ;-)
(Firma: Torrox.de)
Blub schrieb:

> Was ist denn besser?

Übrigens kann man auch das Ergebnis von boolschen Operatoren in einer 
Variablen zwischenspeichern, wenn das ggf. die Lesbarkeit erhöht.
1
  bool first_parameter_valid  = p1 >= 4 && p1 < 20;
2
  bool second_parameter_valid = p2 >= 3 && p2 < 99;
3

4
  if ( first_parameter_valid && second_parameter_valid )
5
    ...

mfg Torsten
Gast
Torsten R. schrieb:
> Übrigens kann man auch das Ergebnis von boolschen Operatoren in einer
> Variablen zwischenspeichern, wenn das ggf. die Lesbarkeit erhöht.
1
>   bool first_parameter_valid  = p1 >= 4 && p1 < 20;
2
>   bool second_parameter_valid = p2 >= 3 && p2 < 99;
3
> 
4
>   if ( first_parameter_valid && second_parameter_valid )
5
>     ...

das erhöht aber kaum die Lesbarkeit gegenüber
1
    if( (p1>=4 && p1<20) && (p2>=3 && p2<99) )
2
        ...

Dann lieber an den Rangeprüfungen arbeiten:
1
    if(   inrange(p1, 4, 19) 
2
       && inrange(p2, 3, 98)
3
      )
4
        ...
Gast
lesbarer wird es noch in C++ mit Classen und Templates
1
#include "Range.hpp"
2
Range<int> LimitP1(4,19);
3
Range<int> LimitP2(3,98);
4

5

6

7
.
8
.
9
.
10
if (LimitP1.InRange(p1) && LimitP2.InRange(p2))
11
{
12
   ...
13
}

lesbarer wäre noch (pseudo code)
1
if (p1.InRange(LimitP1) && p2.InRange(LimitP2))
Gast
Torsten R. schrieb:
> Achim, das war nur ein Beispiel! ;-)

Das verstehe ich, Torsten, und mit Deinem Beispiel bist Du konform zu 
Lehrbüchern für guten Code. Vor allem, wenn man McCabe und anderen 
Metriken folgt, ebenso TTD (Unittests), und vorwiegend orthogonale, 
unabhängige Modulen von je ~1000 Zeilen programmiert.

Sobald man größere Projekte hat, mit Modulen von mehrern 1000 Zeilen und 
einer durch die reale Welt intensiven faktische Verknüpfung, dann rückt 
ein Problem in den Vordergund: Die Lesbarkeit (Geschwindigkeit) des 
Quellcodes. Und hier die Begrenzung von Token sowie die Anzahl der 
Indirektionsebenen.

Hier als Beispiel: Diese if-Schleife wurde durchlaufen, und jemand fragt 
sich, wieso. Wenn dort alle 100 Abfragen direkt untereinander stehen, 
kann er diese (mit dem Auge) scannen und ggf. direkt mit seiner IDE 
nähere Informatione zu p1 oder p2 bekommen. Bei first_parameter_valid 
muss er dazu erst dorthin springen.

Viele Funktionen, die Mc-Cabe senken oder Unittests vereinfachen sollen, 
erschweren real die Lesbarkeit und machen den Code (durch weggekapselten 
Kontext) unsicherer.
Moderator Persönliche Seite
Torsten R. schrieb:
> Übrigens kann man auch das Ergebnis von boolschen Operatoren in einer
> Variablen zwischenspeichern, wenn das ggf. die Lesbarkeit erhöht.

Dann fällt aber (zumindest teilweise) die genannte short-circuit
evaluation weg.  Bei deinen einfachen Variablenabfragen mag das
egal sein, aber wenn zwischendrin eine komplexere Funktion aufgerufen
wird, berechnest du ggf. ein Ergebnis, welches für die Katz' ist.

Noch schlimmer, das Ergebnis könnte undefiniert sein oder eine
Speicherschutzverletzung bringen.  Überleg' dir mal, wie du das
mit dem Zwischenspeichern in Variablen hier machst bzw. was dann
passiert:
1
   if (ptr != NULL && eval_data(ptr->data) != 42) {
2
      // …
3
   }

Danach weißt du, warum man eine wohldefinierte short-circuit
evaluation in einer Sprache braucht.  (Pascal hatte sie zumindest
im ersten Standard nicht, sondern hat es dem Compiler überlassen.
In der Folge musste man dann immer zweimal if verschachteln.)
(Firma: Torrox.de)
Jörg W. schrieb:

> Überleg' dir mal, wie du das
> mit dem Zwischenspeichern in Variablen hier machst bzw. was dann
> passiert:
>
>
1
>    if (ptr != NULL && eval_data(ptr->data) != 42) {
2
>       // …
3
>    }
4
>

Na, der "übliche" Weg ist dann, den Ausdruck schrittweise zu entwickeln:
1
const bool data_exists = ptr != 0;
2
const bool not_42      = data_exists && eval_data(ptr->data) != 42;


versteht mich nicht falsch, ich sage nicht, dass diese der einzige, 
wahre Weg ist! Ich wollte nur darauf hinweisen, dass dies ein Mittel 
sein kann, die Lesbarkeit zur erhöhen (Zitat: "wenn das ggf. die 
Lesbarkeit erhöht.")

Und ja, natürlich muss man short circuit berücksichtigen. Das muss man 
aber auch, wenn man den gesamten Ausdruck in einem hinschreibt.
(Firma: Torrox.de)
Rufus Τ. F. schrieb:
> Torsten R. schrieb:
>> const bool not_42      = data_exists && eval_data(ptr->data) != 42;
>
> Das aber setzt zwingend funktionierende short-circuit evaluation
> voraus, sonst knallt's, wenn ptr dereferenziert wird, um "eval_data"
> aufzurufen.

Oh mann, ließt den hier niemand mehr, sondern stürzt sich nur noch auf 
das letzte Posting?

Sorry, aber ich bin jetzt raus.
Rufus Τ. F. schrieb:
> Keine Ahnung, was "leßen" sein soll - aber in einer Diskussion, wo um
> die Notwendigkeit oder nicht-Existenz der "short circuit evaluation"
> gestritten wird ... nehme ich den Thread vermutlich anders wahr als Du.

Naja, so ganz nachvollziehen kann ich den Sinn deines Postings aber auch 
nicht. Nachdem Torsten meinte, dass man
1
   if (ptr != NULL && eval_data(ptr->data) != 42) {
z.B. auch durch
1
const bool data_exists = ptr != 0;
2
const bool not_42      = data_exists && eval_data(ptr->data) != 42;
ersetzen könnte, meinst du, dass das aber zwingend short-circuit 
evaluation benötigt. Das hat aber das Original auch schon. Außerdem 
hatte er das in seinem Posting schon selber explizit erwähnt:

Torsten R. schrieb:
> Und ja, natürlich muss man short circuit berücksichtigen. Das muss man
> aber auch, wenn man den gesamten Ausdruck in einem hinschreibt.
Moderator
Dumdi D. schrieb:
> und hier das ärgerliche: beim überladenen && (in c++) gibt es wohl keine
> short-circuit evaluation.

Wozu brauchst du das? Der Short-Circuit macht ja nur dann Sinn, wenn die
Operanden wie boolesche Werte behandelt werden können. Dann kannst du
für den neuen Datentyp aber auch einfach eine Konvertierungsfunktion
nach bool (operator bool()) schreiben und die normale &&-Operation mit
Short-Circuit verwenden.

Oder nimm Haskell ;-)

Da wird defaultmäßig lazy evaluiert, was das Short-Circuiting innerhalb
einer selbstgeschriebenen Funktion automatisch nach außen trägt. Solche
Funktonen wie && und || sind dort überhaupt nichts Spezielles und auch
nicht auf boolesche Werte beschränkt.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 10 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.