it-swarm.dev

Ternärer Operator als schädlich eingestuft?

Würden Sie zum Beispiel diesen Einzeiler bevorzugen?

int median(int a, int b, int c) {
    return (a<b) ? (b<c) ? b : (a<c) ? c : a : (a<c) ? a : (b<c) ? c : b;
}

oder eine if/else-Lösung mit mehreren return-Anweisungen?

Wann ist ?: angemessen, und wann ist es nicht? Sollte es Anfängern beigebracht oder vor ihnen verborgen werden?

82
fredoverflow

Ist der ternäre Operator böse?

Nein, es ist ein Segen.

Wann ist ?: Angemessen?

Wenn es so einfach ist, möchten Sie nicht viele Zeilen verschwenden.

und wann ist es nicht

Wenn die Lesbarkeit und Klarheit des Codes leidet und die Gefahr eines Fehlers durch unzureichende Aufmerksamkeit beispielsweise bei vielen verketteten Operatoren zunimmt, wie in Ihrem Beispiel.


Der Lackmustest ist, wenn Sie anfangen zu bezweifeln, dass Ihr Code auf lange Sicht leicht lesbar und wartbar ist. Dann tu es nicht.

236
user8685

Ich denke, der nicht verschachtelte ternäre Operator (d. H. Eine Anweisung, bei der er nur einmal verwendet wird) ist in Ordnung, aber wenn Sie mehr als einen verschachteln, wird es etwas schwer zu lesen.

50
mipadi

Wann ist ?: Angemessen

  • Wenn es Ihren Code prägnanter und lesbarer macht.

und wann ist es nicht

  • Wenn es Ihren Code unlesbar macht.
  • Wenn Sie dies nur tun, um einem Refactoring-Tool wie ReSharper zu gefallen, und nicht der Person, die den Code pflegen muss

Wenn Sie Logik- oder Funktionsaufrufe im ternären Ausdruck haben, ist es schrecklich, sie anzusehen.

24
realworldcoder

Ein Unterschied, auf den (glaube ich) niemand hingewiesen hat, ist, dass if-else keinen Wert zurückgeben kann, während der ternäre Operator dies kann.

Aus F # kommend verwende ich manchmal gerne den ternären Operator, um den Mustervergleich nachzuahmen.

match val with
| A -> 1
| B -> 3
| _ -> 0

vs.

return val == A ? 1 : 
       val == B ? 3 : 
       0;
23
Benjol

Ein Beispiel (IMHO) für eine gültige Verwendung:

printf("Success in %d %s\n", nr_of_tries, (nr_of_tries == 1 ? "try" : "tries"));

Dies führt zu besser lesbarem Code als zwei unterschiedliche Druckanweisungen. Verschachtelte Beispiele hängen ab von: (verständlich? Ja: nein)

13
Henno Brandsma

Absolut nicht böse. Tatsächlich ist es rein und wenn-dann-sonst nicht.

In funktionalen Sprachen wie Haskell, F #, ML usw. werden die Wenn-Dann-Sonst-Aussagen als böse angesehen.

Der Grund dafür ist, dass jede "Aktion" wie eine zwingende if-then-else-Anweisung erfordert, dass Sie eine Variablendeklaration von ihrer Definition trennen und state in Ihre Funktion einführen.

Zum Beispiel im folgenden Code:

const var x = n % 3 == 1
    ? Parity.Even
    : Parity.Odd;

vs.

Parity x;
if (n % 3 == 1)
    x = Parity.Even;
else
    x = Parity.Odd;

Der erste hat zwei Vorteile, abgesehen davon, dass er kürzer ist:

  1. x ist eine Konstante und bietet daher eine viel geringere Wahrscheinlichkeit, Fehler einzuführen, und kann möglicherweise so optimiert werden, wie es die zweite niemals sein könnte.
  2. Der Typ wird durch den Ausdruck verdeutlicht, sodass der Compiler mühelos schließen kann, dass x vom Typ Parity sein muss.

Verwirrenderweise wird der ternäre Operator in funktionalen Sprachen oft als Wenn-Dann-Sonst bezeichnet. In Haskell könnte man sagen x = if n mod 3 == 1 then Odd else Even.

7
Rei Miyasaka

Dieser besondere Ausdruck macht meine Augen weh; Ich würde jeden Entwickler in meinem Team auspeitschen, der es verwendet hat, weil es nicht zu warten ist.

Ternäre Operatoren sind nicht böse, wenn sie gut verwendet werden. Sie müssen nicht einmal einzelne Zeilen sein; Eine lange, gut formatierte Version kann sehr klar und leicht zu verstehen sein:

return
      ( 'a' == $s ) ? 1
    : ( 'b' == $s ) ? 2
    : ( 'c' == $s ) ? 3
    :                 4;

Ich mag das besser als die äquivalente if/then/else-Kette:

if ( 'a' == $s ) {
    $retval = 1;
}
elsif ( 'b' == $s ) {
    $retval = 2;
}
elsif ( 'c' == $s ) {
    $retval = 3;
}
else {
    $retval = 4;
}

return $retval;

Ich werde diese neu formatieren in:

if    ( 'a' == $s ) { $retval = 1; }
elsif ( 'b' == $s ) { $retval = 2; }
elsif ( 'c' == $s ) { $retval = 3; }
else                { $retval = 4; }

return $retval;

wenn die Bedingungen und Zuordnungen eine einfache Ausrichtung ermöglichen. Trotzdem bevorzuge ich die ternäre Version, weil sie kürzer ist und nicht so viel Lärm um die Bedingungen und Aufgaben hat.

7
the Tin Man

ReSharper in VS.NET schlägt manchmal vor, if...else Durch den Operator ?: Zu ersetzen.

Es scheint, dass ReSharper nur vorschlägt, wenn die Bedingungen/Blöcke unter einem bestimmten Komplexitätsniveau liegen, andernfalls bleibt es bei if...else.

3
Uwe Keim

Hier ist ein Beispiel dafür, wann es ist böse:

oldValue = newValue >= 0 ? newValue : oldValue;

Es ist verwirrend und verschwenderisch. Der Compiler konnte den zweiten Ausdruck (oldValue = oldValue) optimieren, aber warum hat der Codierer dies überhaupt getan?

Ein weiterer Trottel:

thingie = otherThingie != null ? otherThingie : null;

Manche Leute sind einfach nicht als Programmierer gedacht ...

Greg sagt, dass die äquivalente if-Anweisung "laut" ist. Es ist, wenn Sie es laut schreiben. Aber das gleiche, wenn geschrieben werden kann als:

if ('a' == $s) return 1;
if ('b' == $s) return 2;
if ('c' == $s) return 3;
return 4;

Welches ist nicht lauter als das ternäre. Ich frage mich, ob die ternären Abkürzungen; Werden alle Ausdrücke ausgewertet?

2
hapybrian

Weit davon entfernt, böse zu sein, ist der ternäre Operator ein Glücksfall.

  • Dies ist am nützlichsten, wenn Sie eine Entscheidung in einem verschachtelten Ausdruck treffen möchten. Das klassische Beispiel ist ein Funktionsaufruf:

    printf("I see %d evil construct%s in this program\n", n, n == 1 ? "" : "s");
    
  • In Ihrem speziellen Beispiel ist das Ternär fast unbegründet, da es der Ausdruck der obersten Ebene unter einem return ist. Sie können die Bedingung auf die Anweisungsebene heben, ohne etwas anderes als das Schlüsselwort return zu duplizieren.

N.B. Nichts wird diesen speziellen Algorithmus für den Median jemals leicht lesbar machen.

2
Norman Ramsey
  1. Abgesehen von "bösen" Argumenten habe ich meiner Erfahrung nach eine hohe Korrelation zwischen der Verwendung des ternären Operators durch einen Programmierer und der Wahrscheinlichkeit festgestellt, dass seine gesamte Codebasis schwer zu lesen, zu befolgen und zu warten ist (wenn nicht vollständig undokumentiert). Wenn es einem Programmierer mehr darum geht, ein paar Zeilen mit 1 bis 2 Zeichen zu speichern, als dass jemand seinen Code verstehen kann, ist jede kleine Verwirrung, die eine ternäre Aussage versteht, normalerweise die Spitze des Eisbergs.

  2. Ternäre Operatoren ziehen magische Zahlen an, wie s ** t Fliegen anzieht.

Wenn ich nach einer Open Source-Bibliothek suchte, um ein bestimmtes Problem zu lösen, und Code wie die ternären Operatoren des Originalplakats in einem Kandidaten für diese Bibliothek sah, würden Warnglocken in meinem Kopf losgehen und ich würde darüber nachdenken, weiterzumachen zu einem anderen Projekt zu leihen.

2
user8865

Böse? Schau, sie sind einfach anders.

if ist eine Anweisung. (test ? a : b) ist ein Ausdruck. Sie sind nicht dasselbe.

Ausdrücke existieren, um Werte auszudrücken. Anweisungen sind vorhanden, um Aktionen auszuführen. Ausdrücke können in Anweisungen erscheinen, aber nicht umgekehrt. Sie können also ternäre Ausdrücke in anderen Ausdrücken verwenden, z. B. für Begriffe in einer Summierung oder für Argumente für eine Methode usw. Sie nicht müssen, aber Sie können, wenn Sie wollen. Daran ist nichts auszusetzen. Einige Leute mögen sagen, dass das böse ist, aber das ist ihre Meinung.

Ein Wert eines ternären Ausdrucks besteht darin, dass Sie sowohl wahre als auch falsche Fälle behandeln können. if Anweisungen nicht.

Wenn Sie sich Sorgen um die Lesbarkeit machen, können Sie sie lesbar formatieren.

Irgendwie hat sich "böse" in das Programmiervokabular eingeschlichen. Ich würde gerne wissen, wer es zuerst fallen ließ. (Eigentlich habe ich einen Verdächtigen - er ist am MIT.) Ich hätte lieber objektive Gründe für Werturteile in diesem Bereich, nicht nur den Geschmack und die Namensgebung der Menschen.

2
Mike Dunlavey

Dies kann neu formatiert werden, um so gut auszusehen wie die if/else-Kombination:

int median(int a, int b, int c)
{
    return
        (a<b)
        ?
            (b<c)
            ? b
            :
                (a<c)
                ? c
                : a
        :
            (a<c)
            ? a
            :
                (b<c)
                ? c
                : b;
}

Das Problem ist jedoch, dass ich nicht wirklich sicher bin, ob ich die Einrückung richtig verstanden habe, um darzustellen, was tatsächlich passieren wird. :-)

2
Zan Lynx

Kann ich das sagen Ich kann diese spezielle Anwendung der ternären Operation nicht finden böse:

  1. die Operation, die es ausführt, ist ziemlich trivial, und wenn Sie sie einmal durchlaufen haben, ist es kaum möglich, dass einige Fehler auftreten.
  2. was es tut, ist im Funktionsnamen klar angegeben;
  3. > 1 Zeile für etwas so Offensichtliches zu nehmen, und das würde sich in Zukunft eindeutig nicht verbessern (es sei denn, ein magischer Median-Algorithmus hat bis jetzt unentdeckt gelebt).

Bitte erbarme dich, mein Ruf ist schon ziemlich erbärmlich.

1
cbrandolino

Alles, was Ihren Code hässlicher macht, ist böse.

Wenn Sie ternary verwenden, um Ihren Code sauberer zu machen, verwenden Sie ihn auf jeden Fall. Manchmal ist es in ähnlichem PHP großartig, Inline-Substitutionen durchzuführen, z.

"Hello ".($Male?"Mr":"Ms")." $Name

Das spart ein paar Zeilen, und es ist ziemlich klar, aber Ihr Beispiel benötigt zumindest eine bessere Formatierung, um klar zu sein, und ternär ist nicht wirklich gut für mehrzeilige Zeilen. Dann können Sie es auch verwenden, wenn/else.

1
user11134

Größter Gewinn: Zeigen, dass es ein einziges Aktionsziel gibt.

if ( $is_whatever )
    $foo = 'A';
else
    $foo = 'B';

Es gibt zwei Codepfade, denen Sie folgen können, und der Leser muss sorgfältig lesen, um zu sehen, welche zwei Variablen festgelegt werden. In diesem Fall ist es nur eine Variable, aber der Leser muss mehr lesen, um das herauszufinden. Immerhin könnte es das gewesen sein:

if ( $is_whatever )
    $foo = 'A';
else
    $bar = 'B';

Mit dem ternären Operator ist klar, dass nur eine Variable gesetzt wird.

$foo = $is_whatever ? 'A' : 'B';

Auf der untersten Ebene ist es das Prinzip DRY (Wiederholen Sie sich nicht)) in seiner grundlegendsten Form. Wenn Sie $foo Nur einmal angeben können, tun Sie dies.

1
Andy Lester

Es hat einen Platz. Ich habe in vielen Unternehmen gearbeitet, in denen die Fähigkeiten von Entwicklern von schrecklich bis zauberhaft reichen. Da der Code gepflegt werden muss und ich nicht für immer da sein werde, versuche ich, Dinge so zu schreiben, dass sie so aussehen, als ob sie dort hingehören (ohne die Kommentare mit meinen Initialen zu lesen, ist es äußerst selten, dass Sie dazu in der Lage sind Schauen Sie sich den Code an, an dem ich gearbeitet habe, um zu sehen, wo ich Änderungen vorgenommen habe, und dass jemand mit weniger Fähigkeiten als ich ihn pflegen kann.

Während der ternäre Operator nitzig und cool aussieht, ist es meiner Erfahrung nach unmöglich, die Codezeile zu warten. Bei meinem derzeitigen Arbeitgeber haben wir Produkte, die seit fast 20 Jahren ausgeliefert werden. Ich würde dieses Beispiel nirgendwo verwenden.

1
Tangurena

Ich denke nicht, dass der ternäre Operator böse ist.

Hier ist ein Gotcha, der mich allerdings verblüfft hat. Ich war ein C-Programmierer für viele (10+) und in den späten 1990er Jahren wechselte ich in die webbasierte Anwendungsprogrammierung. Als Webprogrammierer stieß ich bald auf PHP, das auch einen ternären Operator hat. Ich hatte einen Fehler in einem PHP -Programm, das ich schließlich auf eine Zeile zurückführte von Code mit einem verschachtelten ternären Operator. Es stellt sich heraus, dass der ternäre Operator PHP von links nach rechts, aber der ternäre Operator C, an den ich gewöhnt war) von rechts nach links assoziiert.

1
leed25d

Wann ist angemessen und wann nicht?

Ich denke, wenn Sie sich für eine homogene Gruppe von Menschen entwickeln, gibt es kein Problem, aber wenn Sie sich mit Menschen befassen müssen, die mit verschiedenen Ebenen umgehen, führen diese Oneliner nur eine weitere Ebene von Komplexitäten in den Code ein. Meine Politik in dieser Angelegenheit lautet also: Code klar und nicht erklären statt Code kurz und 123123 mal erklären.

Sollte es Anfängern beigebracht oder vor ihnen verborgen werden?

Ich sollte Anfängern nicht beigebracht werden, sondern sie vorziehen, um herauszufinden, wann es nötig ist. Daher wird es nur verwendet, wenn es erforderlich ist, und nicht jedes Mal, wenn Sie ein Wenn benötigen.

0
guiman

Ein Geschäft, das regelmäßig Methoden mit 600-1200 Zeilen schreibt sollte nicht mir sagen, dass ein Ternär "schwer zu verstehen" ist. Jeder Shop, der regelmäßig fünf Bedingungen zur Auswertung eines Code-Zweigs zulässt sollte nicht mir sagen, dass konkret zusammengefasste Bedingungen in einem Ternär "schwer zu lesen" sind.

0
Axeman

IMO, der Operator selbst ist nicht böse, aber die dafür in C (und C++) verwendete Syntax ist zu knapp. IMO, ALGOL 60 hat es besser gemacht, also so etwas:

A = x == y ? B : C;

würde eher so aussehen (aber generell an der C-ähnlichen Syntax festhalten):

A = if (x==y) B else C;

Trotzdem kann eine zu tiefe Verschachtelung zu Problemen mit der Lesbarkeit führen, aber zumindest A) jeder, der überhaupt programmiert hat, kann es einfach herausfinden, und B) Leute, die es verstehen, können ziemlich leicht mit einer erheblich tieferen Verschachtelung umgehen. OTOH, ich würde auch bemerken, dass in LISP (zum Beispiel) ein cond einer ternären Anweisung ziemlich ähnlich ist - keine Menge von Anweisungen, sondern ein einzelner Ausdruck, der einen Wert ergibt (andererseits die meisten LISP ist so ...)

0
Jerry Coffin

Wann ist ?: Angemessen und wann nicht?

  • Wenn Sie keinen Leistungsgewinn erzielen, verwenden Sie ihn nicht. Dies beeinträchtigt die Lesbarkeit Ihres Codes.
  • Verwenden Sie es einmal und verschachteln Sie es nicht.
  • Das Debuggen ist schwieriger.

Sollte es Anfängern beigebracht oder vor ihnen verborgen werden?

Es spielt keine Rolle, aber es sollte nicht absichtlich versteckt werden, da es für einen „Anfänger“ nicht zu komplex ist, um es zu lernen.

0
Amir Rezaei

Wenn ... dann ... neigt dazu, den Zustand zu betonen und daher die Operationen, die bedingt ausgeführt werden, zu betonen.

der ternäre Operator ist das Gegenteil, er neigt dazu, die Bedingung zu verbergen, und ist daher nützlich, wenn die ausgeführte Operation wichtiger ist als die Bedingung selbst.

In einigen Sprachen gibt es das kleine technische Problem, dass sie nicht ganz austauschbar sind, da eines eine Aussage und eines ein Ausdruck ist, z. Bedingte Initialisierung von Konstanten in C++

0
jk.