Warum haben "if elif else" -Anweisungen so gut wie nie das Format einer Tabelle?

73
if   i>0 : return sqrt(i)  
elif i==0: return 0  
else     : return 1j * sqrt(-i)

VS

if i>0:  
   return sqrt(i)  
elif i==0:  
   return 0  
else:  
   return 1j * sqrt(-i)  

Angesichts der obigen Beispiele verstehe ich nicht, warum ich den ersten Stil in Codebasen so gut wie nie sehe. Für mich wandeln Sie den Code in ein Tabellenformat um, das klar zeigt, was Sie wollen. Die erste Spalte kann praktisch ignoriert werden. Die zweite Spalte gibt den Zustand an und die dritte Spalte gibt Ihnen die gewünschte Ausgabe. Zumindest scheint es mir einfach und leicht zu lesen zu sein. Ich sehe diese einfache Art von Fall / Schalter-Situation jedoch immer im erweiterten Format mit eingerückten Tabulatoren. Warum ist das so? Finden die Leute das zweite Format besser lesbar?

Dies kann nur dann problematisch sein, wenn sich der Code ändert und länger wird. In diesem Fall halte ich es für absolut sinnvoll, den Code in das lange, eingerückte Format umzugestalten. Tun es alle auf die zweite Art und Weise, nur weil es immer so war? Als Anwalt eines Teufels kann ein weiterer Grund darin liegen, dass die Leute zwei unterschiedliche Formate finden, abhängig von der Komplexität der if / else-Anweisungen, die sie für verwirrend halten. Jede Einsicht wäre dankbar.

Horta
quelle
91
Weil die Leute die 2. Option besser lesbar finden?
GroßmeisterB
65
Der Anwendungsfall von sich gegenseitig ausschließenden Zweigen, bei denen alle einen Wert desselben Typs zurückgeben, tritt in imperativen Sprachen seltener auf als bei Zweigen, bei denen möglicherweise keine Werte zurückgegeben werden, die sich über mehrere Zeilen erstrecken und möglicherweise Nebenwirkungen haben. Wenn Sie sich funktionierende Programmiersprachen ansehen, werden Sie häufiger Code sehen, der Ihrem ersten Beispiel ähnelt.
Doval
47
@horta "Der einzige Fall, in dem dies problematisch sein könnte, ist, dass sich der Code ändert und länger wird." - Sie sollten NIEMALS davon ausgehen, dass ein Teil des Codes nicht geändert wird. Code-Refactoring nimmt einen großen Teil des Lebenszyklus einer Software ein.
Charles Addis
7
@horta: Nichts mit mir zu tun. Es ist der Code. Im Zusammenhang mit der Codebasis, die ich lese, möchte ich sehen, ob Anweisungen (und andere Sprachkonstrukte) ohne Randfälle konsistent formatiert sind. Es ist nicht so, dass ich gelernt hätte, Code auf eine bestimmte Art und Weise zu lesen. Ich kann beide gut lesen, aber es ist besser lesbar, wenn alles gleich ist. Wieder nicht das Gleiche für mich, das Gleiche für den Rest des Codes.
GManNickG
44
Außerdem sind die meisten Debugger zeilenbasiert. Es kann kein Haltepunkt für eine Anweisung innerhalb von gesetzt werden, ifwenn sie sich in derselben Zeile befindet.
Isanae

Antworten:

93

Ein Grund kann sein, dass Sie keine Sprachen verwenden, in denen es beliebt ist.

Einige Gegenbeispiele:

Haskell mit Wachen und mit Mustern:

sign x |  x >  0        =   1
       |  x == 0        =   0
       |  x <  0        =  -1

take  0     _           =  []
take  _     []          =  []
take  n     (x:xs)      =  x : take (n-1) xs

Erlang mit Mustern:

insert(X,Set) ->
    case lists:member(X,Set) of
        true  -> Set;
        false -> [X|Set]
    end.

Emacs lisp:

(pcase (get-return-code x)
  (`success       (message "Done!"))
  (`would-block   (message "Sorry, can't do it now"))
  (`read-only     (message "The shmliblick is read-only"))
  (`access-denied (message "You do not have the needed rights"))
  (code           (message "Unknown return code %S" code)))

Im Allgemeinen sehe ich, dass das Tabellenformat bei funktionalen Sprachen (und im Allgemeinen bei auf Ausdrücken basierenden) ziemlich beliebt ist, während das Brechen von Zeilen bei anderen am beliebtesten ist (meistens auf Anweisungen basierend).

viraptor
quelle
10
Ich habe dem zugestimmt und bin damit einverstanden, fühle mich aber verpflichtet, darauf hinzuweisen, dass 1. dies alles triviale Renditen sind und sogar imperative Sprachen haben andere Standards für Ausdrücke als Anweisungen. Wenn das OP das ursprüngliche Beispiel als Funktionsanwendungen umschrieb, könnte er andere Ratschläge erhalten ...
Jared Smith
3
@JaredSmith Vielen Dank für die auf Ausdrücken / Anweisungen basierende Aufteilung - ich denke, es ist vielleicht noch passender als funktional / zwingend. Dann ist Ruby fast ausdrucksorientiert und verwendet diese Konvention nicht oft. (Ausnahmen zu allem) In Bezug auf die Punkte 1 und 2 stelle ich fest, dass 50% + des echten Haskell-Codes "triviale Renditen" sind, die nur Teile von etwas Größerem sind - es ist nur so, wie dieser Code geschrieben ist - nicht nur in den Beispielen hier. Nahezu die Hälfte der Funktionen sind hier beispielsweise nur ein / zwei Liner. (Einige Zeilen verwenden Tabellenlayout)
Viraptor
Ja. Ich bin kein Haskeller, aber mache ein paar Dinge und finde, dass Pattern Matching viel prägnanter ist als logisch äquivalente Schalter, und polymorphe Funktionen decken sowieso einen Großteil dieses Gebiets ab. Ich stelle mir vor, dass Haskells Typenklassen diese Abdeckung noch weiter ausbauen würden.
Jared Smith
Ich denke, es ist die Pattern-Case-Syntax, die das fördert. Da es prägnanter ist und sich normalerweise eher einem kurzen Schaltergehäuse nähert, ist es einfacher, es als Einzeiler auszudrücken. Ich mache dies aus ähnlichen Gründen häufig auch mit kurzen switch-case-Anweisungen. Literalaussagen if-elsesind jedoch in der Regel immer noch auf mehrere Zeilen verteilt, wenn es sich nicht um einfache ternäre Ausdrücke handelt.
Isiah Meadows
@viraptor Technisch gesehen sind die anderen 50% des Haskell-Codes "nicht triviale Erträge", da alle Haskell-Funktionen funktionsrein sind und keine Nebenwirkungen haben können. Sogar Funktionen, die von der Befehlszeile gelesen und in diese ausgegeben werden, sind nur langwierige return-Anweisungen.
Pharap
134

Es ist besser lesbar. Ein paar Gründe warum:

  • Fast jede Sprache verwendet diese Syntax (nicht alle, die meisten - Ihr Beispiel scheint jedoch Python zu sein).
  • isanae wies in einem Kommentar darauf hin, dass die meisten Debugger zeilenbasiert sind (nicht anweisungsbasiert )
  • Es sieht sogar noch hässlicher aus, wenn Sie Semikolons oder geschweifte Klammern einfügen müssen
  • Es liest sich besser von oben nach unten
  • Es sieht schrecklich unlesbar aus, wenn Sie etwas anderes als triviale Rückgabeanweisungen haben
    • Jede einrückende sinnvolle Syntax geht verloren, wenn Sie Code überfliegen, da der bedingte Code nicht mehr visuell getrennt ist (von Dan Neely ).
    • Dies ist besonders schlimm, wenn Sie weiterhin Elemente in die 1-zeilige if-Anweisung einfügen
  • Es ist nur lesbar, wenn alle Ihre Schecks ungefähr gleich lang sind
  • Dies bedeutet, dass Sie komplizierte Anweisungen nicht in mehrzeilige Anweisungen formatieren können. Sie müssen Oneliners sein
  • Es ist weitaus wahrscheinlicher, dass ich Fehler / Logikflüsse bemerke, wenn ich vertikal zeilenweise lese und nicht versuche, mehrere Zeilen zusammen zu analysieren
  • Unser Gehirn liest schmaleren, größeren Text VIEL schneller als langen, horizontalen Text

In dem Moment, in dem Sie dies versuchen, werden Sie es in mehrzeilige Anweisungen umschreiben. Was bedeutet, dass Sie nur Zeit verschwendet haben!

Man fügt auch unweigerlich Folgendes hinzu:

if i>0:  
   print('foobar')
   return sqrt(i)  
elif i==0:  
   return 0  
else:  
   return 1j * sqrt(-i)  

Es dauert nicht sehr oft, bis Sie feststellen, dass dieses Format viel besser ist als Ihre Alternative. Ah, aber Sie könnten alles in eine Zeile schreiben! Enderland stirbt an der Innenseite .

Oder dieses:

if   i>0 : return sqrt(i)  
elif i==0 and bar==0: return 0  
else     : return 1j * sqrt(-i)

Was sehr, sehr ärgerlich ist. Niemand mag es, solche Dinge zu formatieren.

Und zuletzt werden Sie den heiligen Krieg des Problems "Wieviel Platz für Tabs?" Beginnen. Was auf Ihrem Bildschirm als Tabellenformat perfekt dargestellt wird, wird auf meinem möglicherweise nicht dargestellt, abhängig von den Einstellungen.

Die Lesbarkeit sollte sowieso nicht von den IDE-Einstellungen abhängen.

Enderland
quelle
14
@horta, weil Sie es konvertieren müssen , wenn Sie es zuerst formatieren? Mir geht es darum, die Arbeit für das zukünftige Enderland zu minimieren. Erstellen Sie hübsche Whitespace-Tabellen und zählen Sie Leerzeichen und Tabulatoren, um die visuelle Formatierung zu aktualisieren, wenn ich einem If-Check etwas Logik hinzufügen möchte (ohne Berücksichtigung der Auswirkungen auf die Lesbarkeit).
Enderland
14
@horta Er sagt nicht unbedingt, dass er es nicht reparieren würde, er sagt, dass er es reparieren müsste, und das ist eine Menge Zeit, die für mühsames Formatieren und nicht für Programmieren aufgewendet wird.
Servy
11
@horta: IMHO ist dein Weg oft weniger lesbar und ist definitiv viel ärgerlicher zu formatieren. Es kann auch nur verwendet werden, wenn die "Wenn" kleine Einzeiler sind, was selten der Fall ist. Schließlich ist es meiner Meinung nach irgendwie nicht schön, zwei Arten von "Wenn" -Formatierungen herumzutragen.
Dagnelies
9
@horta Sie scheinen gesegnet zu sein, auf Systemen zu arbeiten, auf denen sich Anforderungen, Systeme, APIs und Benutzeranforderungen nie ändern. Du glückliche Seele.
Enderland
11
Ich würde hinzufügen: Jede kleine Änderung in einer einzelnen Bedingung kann eine Neuformatierung der anderen erfordern, um sie an die :Position anzupassen.> Wenn Sie in einem CVS einen Unterschied machen, wird es plötzlich schwieriger zu verstehen, was sich tatsächlich ändert. Dies gilt auch für den Zustand gegen den Körper. Wenn Sie sie in getrennten Zeilen haben, bedeutet dies, dass die Unterschiede deutlich zeigen, dass sich nur der Zustand geändert hat, nicht der Körper.
Bakuriu
55

Ich bin fest davon überzeugt, dass "Code viele Male gelesen und nur wenige Male geschrieben wird - daher ist die Lesbarkeit sehr wichtig."

Eine wichtige Sache, die mir hilft, wenn ich den Code anderer Leute lese, ist, dass ich den „normalen“ Mustern folge, die meine Augen erkennen sollen. Ich kann das eingerückte Formular am einfachsten lesen, weil ich es so oft gesehen habe, dass es fast automatisch registriert wird (mit wenig kognitivem Aufwand von meiner Seite). Es ist nicht, weil es "hübscher" ist - es ist, weil es den Konventionen folgt, die ich gewohnt bin. Convention schlägt "besser" ...

Art Swri
quelle
3
Relevant: thecodelesscode.com/case/94
Kevin
11
Dies erklärt, warum die Menschen konservativ sind. Es erklärt nicht, warum die Leute beschlossen haben, ihren Code auf eine bestimmte Art und Weise zu schreiben.
Jørgen Fogh
8
Die Frage war, warum ich das oft sehe und nicht, woher dieser Stil kommt. Beide Fragen sind interessant; Ich habe versucht, die zu beantworten, von der ich dachte, dass sie gefragt wird.
Art Swri
16

Zusammen mit den anderen bereits erwähnten Nachteilen erhöht das Tabellenlayout die Wahrscheinlichkeit von Zusammenführungskonflikten der Versionskontrolle, die manuelles Eingreifen erfordern.

Wenn ein Block mit tabellarischem Code neu ausgerichtet werden muss, behandelt das Versionskontrollsystem jede dieser Zeilen als geändert:

diff --git a/foo.rb b/foo.rb
index 40f7833..694d8fe 100644
--- a/foo.rb
+++ b/foo.rb
@@ -1,8 +1,8 @@
 class Foo

   def initialize(options)
-    @cached_metadata = options[:metadata]
-    @logger          = options[:logger]
+    @metadata = options[:metadata]
+    @logger   = options[:logger]
   end

 end

Angenommen, in der Zwischenzeit hat ein Programmierer in einem anderen Zweig eine neue Zeile zum Block mit ausgerichtetem Code hinzugefügt:

diff --git a/foo.rb b/foo.rb
index 40f7833..86648cb 100644
--- a/foo.rb
+++ b/foo.rb
@@ -3,6 +3,7 @@ class Foo
   def initialize(options)
     @cached_metadata = options[:metadata]
     @logger          = options[:logger]
+    @kittens         = options[:kittens]
   end

 end

Das Zusammenführen dieses Zweigs schlägt fehl:

wayne@mercury:/tmp/foo$ git merge add_kittens
Auto-merging foo.rb
CONFLICT (content): Merge conflict in foo.rb
Automatic merge failed; fix conflicts and then commit the result.

Wenn der zu ändernde Code keine tabellarische Ausrichtung verwendet hätte, wäre die Zusammenführung automatisch erfolgreich gewesen.

(Diese Antwort wurde aus meinem eigenen Artikel "plagiiert", wodurch die tabellarische Ausrichtung im Code erschwert wurde).

Wayne Conrad
quelle
1
Interessant, aber ist das nicht ein Versagen der Merge-Tools? Speziell in diesem Fall git? Dies ist ein Datenpunkt für die Konvention, die der einfachste Weg ist. Für mich ist es etwas, das verbessert werden könnte (von der Werkzeugseite).
Horta
7
@horta Damit das Merge-Tool den Leerraum auf eine Weise ändert, die den Code fast immer beschädigt, muss es verstehen, auf welche Weise der Leerraum geändert werden kann, ohne die Bedeutung des Codes zu ändern. Es muss auch die jeweilige verwendete Tabellenausrichtung verstehen. Das ist nicht nur sprachabhängig (Python!), Sondern erfordert wahrscheinlich das Tool, um den Code bis zu einem gewissen Grad zu verstehen. Auf der anderen Seite kann das zeilenbasierte Zusammenführen ohne KI durchgeführt werden und bricht häufig nicht einmal den Code.
Wayne Conrad
Erwischt. Wie bereits an anderer Stelle in den Kommentaren erwähnt, werden Tooling-Probleme für diejenigen von uns, die Tabellen bevorzugen, immer schwierig sein, bis wir über IDEs oder Programmiereingabeformate verfügen, die Tabellen direkt in das Format einbinden.
Horta
1
@horta Richtig. Die meisten meiner Einwände gegen die tabellarische Ausrichtung im Code könnten mit ausreichend fortschrittlichen Tools beseitigt werden.
Wayne Conrad
8

Tabellenformate können sehr schön sein, wenn die Dinge immer in die zugewiesene Breite passen. Wenn jedoch etwas die zugewiesene Breite überschreitet, ist es häufig erforderlich, entweder einen Teil der Tabelle zu haben, der nicht mit dem Rest der Tabelle ausgerichtet ist, oder das Layout aller anderen Teile der Tabelle so anzupassen, dass sie zum langen Artikel passen .

Wenn Quelldateien mit Programmen bearbeitet wurden, die für die Arbeit mit Daten im Tabellenformat entwickelt wurden und übermäßig lange Elemente mit einer kleineren Schriftgröße verarbeiten konnten, indem sie in zwei Zeilen in derselben Zelle usw. aufgeteilt wurden, ist die Verwendung von Tabellen möglicherweise sinnvoll formatiert häufiger, aber die meisten Compiler möchten Quelldateien, die frei von Markups sind, die solche Editoren speichern müssten, um die Formatierung beizubehalten. Die Verwendung von Zeilen mit variablen Einzügen, aber keinem anderen Layout ist im besten Fall nicht so gut wie die Formatierung von Tabellen, im schlimmsten Fall verursacht sie jedoch nicht annähernd so viele Probleme.

Superkatze
quelle
Wahr. Mir ist aufgefallen, dass der von mir verwendete Texteditor (vim) eine schreckliche Unterstützung für die Formatierung von Tabellen oder sogar für breiten Text bietet. Ich habe nicht gesehen, dass andere Texteditoren viel besser abschneiden.
Horta
6

Es gibt die "switch" -Anweisung, die diese Art von Dingen für Sonderfälle bereitstellt, aber ich denke, das ist nicht das, wonach Sie fragen.

Ich habe gesehen, ob Anweisungen im Tabellenformat, aber es muss eine große Anzahl von Bedingungen geben, damit es sich lohnt. 3 Wenn Anweisungen am besten im herkömmlichen Format angezeigt werden, aber wenn Sie 20 hatten, ist es viel einfacher, sie in einem großen Block anzuzeigen, der zur Verdeutlichung formatiert ist.

Und da ist der Punkt: Klarheit. Wenn dies die Anzeige erleichtert (und Ihr erstes Beispiel nicht leicht erkennen lässt, wo sich das Trennzeichen befindet), formatieren Sie es entsprechend der jeweiligen Situation. Ansonsten bleiben Sie bei dem, was die Leute erwarten, denn das ist immer leichter zu erkennen.

gbjbaanb
quelle
1
OP scheint Python zu verwenden, also nein switch.
Jared Smith
2
"3 wenn Aussagen am besten im herkömmlichen Format angezeigt werden, aber wenn Sie 20 hatten" ... dann haben Sie größere Probleme, über die Sie nachdenken müssen! :)
Grimm Die Opiner
@GrimmTheOpiner Wenn Sie einen Sprachparser oder einen AST-String schreiben, ist das sehr wahrscheinlich. Ich habe zum Beispiel einmal zu einem JavaScript-Parser beigetragen, in dem ich eine Funktion mit 15 bis 20 Fällen aufgeteilt habe, einen für jeden Ausdruckstyp. Ich habe die meisten Fälle nach ihren eigenen Funktionen unterteilt (für einen bemerkenswerten Leistungsschub), aber der lange switchwar eine Notwendigkeit.
Isiah Meadows
@JaredSmith: Anscheinend switchist es böse, ein Wörterbuch zu instanziieren und es dann nachzuschlagen , um triviale Verzweigungen durchzuführen, ist nicht böse ...
Mark K Cowan
1
@MarkKCowan oh, ich habe den Sarkasmus gefangen, dachte aber, du benutzt ihn, um mich zu verspotten. Mangel an Kontext im Internet und so weiter.
Jared Smith
1

Wenn Ihr Ausdruck wirklich so einfach ist, bieten die meisten Programmiersprachen den Verzweigungsoperator?::

return  ( i > 0  ) ? sqrt( i)
      : ( i == 0 ) ? 0
        /* else */ : 1j * sqrt( -i )

Dies ist ein kurzes, lesbares Tabellenformat. Aber das Wichtige ist: Ich sehe auf einen Blick, was die "Hauptaktion" ist. Dies ist eine Rückgabeerklärung! Und der Wert wird von bestimmten Bedingungen bestimmt.

Wenn Sie andererseits Zweige haben, die anderen Code ausführen, finde ich es viel lesbarer, diese Blöcke einzurücken. Denn jetzt gibt es je nach if-Anweisung unterschiedliche "Hauptaktionen". In einem Fall werfen wir, in einem Fall loggen wir uns ein und kehren zurück oder kehren einfach zurück. Abhängig von der Logik gibt es einen unterschiedlichen Programmfluss. Daher kapseln Codeblöcke die verschiedenen Zweige und machen sie für den Entwickler bekannter (z. B. Geschwindigkeitslesen einer Funktion zum Erfassen des Programmflusses).

if ( i > 0 )
{
    throw new InvalidInputException(...);
}
else if ( i == 0 )
{
    return 0;
}
else
{
    log( "Calculating sqrt" );
    return sqrt( -i );
}
Falco
quelle
7
Eigentlich finde ich Ihr "kurz lesbares Tabellenformat" ein ziemlicher Albtraum, während das von OP vorgeschlagene Format völlig in Ordnung ist.
Matteo Italia
@ MatteoItalia wie wäre es mit dieser bearbeiteten Version?
Falco
5
Entschuldigung, noch schlimmer; Ich denke, dass es von der Tatsache herrührt , dass die ?und :schwerer zu erkennen sind als die if/ elsekeywords und / oder aufgrund des hinzugefügten "Rauschens" der Symbole.
Matteo Italia
@ MatteoItalia: Ich hatte Fälle mit über hundert verschiedenen Werten. Mit dem Tabellenwert kann nach Fehlern gesucht werden. Mit Multi-Line ist es unmöglich.
Gnasher729
1
@ gnasher729 - Für 100 verschiedene "Werte" habe ich allgemein festgestellt, dass es viel besser ist, eine Datenstruktur für jedes "Element" zu deklarieren und alles als Tabelle in der Initialisierung für ein Array dieser Datenstrukturen aufzulisten. (Natürlich können hier Spracheinschränkungen gelten). Wenn ein Element einen "rechnerischen" Aspekt erfordert, kann die Elementstruktur einen Zeiger oder eine Referenz auf eine Funktion enthalten, um die erforderliche Aktion auszuführen. Bei einigen Anwendungen kann dies den Code erheblich vereinfachen und die Wartung erheblich vereinfachen.
Michael Karas
1

Wie Enderland bereits sagte, gehen Sie davon aus, dass Sie immer nur ein "Return" als Aktion haben und dass Sie dieses "Return" am Ende der Bedingung markieren können. Ich möchte einige zusätzliche Details nennen, warum dies nicht erfolgreich sein wird.

Ich weiß nicht, welche Sprachen Sie bevorzugen, aber ich habe lange Zeit in C codiert. Es gibt eine Reihe von Codierungsstandards, die darauf abzielen, einige Standardcodierungsfehler zu vermeiden, indem fehleranfällige Codekonstruktionen weder bei der Erstcodierung noch bei der späteren Wartung zugelassen werden. Ich kenne MISRA-C am besten, aber es gibt andere, und im Allgemeinen haben sie alle ähnliche Regeln, weil sie dieselben Probleme in derselben Sprache ansprechen.

Ein beliebter Fehler, den Codierungsstandards häufig ansprechen, ist dieses kleine Problem:

if (x == 10)
    do_something();
    do_something_else();

Das tut nicht das, was du denkst. Für C gilt: Wenn x 10 ist, dann rufst du do_something(), wird dann do_something_else()aber unabhängig vom Wert von x gerufen . Nur die unmittelbar auf die "if" -Anweisung folgende Aktion ist bedingt. Dies könnte das sein, was der Codierer beabsichtigt hat. In diesem Fall gibt es eine potenzielle Falle für Betreuer. oder es ist nicht das, was der Codierer beabsichtigt hat. In diesem Fall liegt ein Fehler vor. Es ist eine beliebte Interviewfrage.

Die Lösung für Codierungsstandards besteht darin, alle bedingten Aktionen in geschweiften Klammern zu setzen, auch wenn sie einzeilig sind. Wir bekommen jetzt

if (x == 10)
{
    do_something();
    do_something_else();
}

oder

if (x == 10)
{
    do_something();
}
do_something_else();

und jetzt funktioniert es richtig und ist für Betreuer klar.

Sie werden feststellen, dass dies nicht mit Ihrem Tabellenformat kompatibel ist.

Einige andere Sprachen (z. B. Python) haben sich mit diesem Problem befasst und entschieden, dass es eine gute Idee ist, anstelle von geschweiften Klammern Leerzeichen zu verwenden, da Codierer Leerzeichen verwenden, um das Layout zu verdeutlichen. Also in Python,

if x == 10:
    do_something()
    do_something_else()

macht die Aufrufe von beiden do_something()und do_something_else()von x == 10 abhängig, wohingegen

if x == 10:
    do_something()
do_something_else()

bedeutet, dass nur do_something()an x gebunden ist und do_something_else()immer aufgerufen wird.

Es ist ein gültiges Konzept und wird von einigen Sprachen verwendet. (Ich habe es zum ersten Mal in Occam2 gesehen, vor langer Zeit.) Auch hier können Sie leicht feststellen, dass Ihr Tabellenformat nicht mit der Sprache kompatibel ist.

Graham
quelle
1
Ich denke, Sie haben den Punkt verpasst. Das Problem, von dem Sie sprechen, ist ein seltsamer C-spezifischer, nicht standardmäßiger Albtraum, der das Problem verursacht, von dem Sie sprechen. Wenn Sie in C codieren, würde ich niemals empfehlen, die alternative simple if-Methode mit dem von mir vorgeschlagenen Tabellenformat zu verwenden. Stattdessen würden Sie, da Sie C verwenden, alle Klammern in einer einzelnen Zeile verwenden. Die geschweiften Klammern würden das Tabellenformat sogar noch deutlicher machen, da sie als Begrenzer fungieren.
Horta
Auch die return-Anweisungen in diesem Fall sind nur ein Beispiel. Im Allgemeinen kann dies ein Codegeruch an sich sein. Ich beziehe mich nur auf das Format einfacher Anweisungen, nicht unbedingt auf return-Anweisungen.
Horta
2
Mein Punkt war, dass dies ein Tabellenformat noch klobiger macht. Im Übrigen ist es nicht C-spezifisch - es wird von allen von C abgeleiteten Sprachen gemeinsam genutzt, sodass C ++, C #, Java und JavaScript alle dasselbe gotcha zulassen.
Graham
1
Es macht mir nichts aus, dass es sich um Rückgabeanweisungen handelt - ich verstehe, dass Ihre Absicht darin besteht, einfache Anweisungen zu zeigen. Aber es wird umständlicher. Und natürlich müssen Sie die Formatierung ändern, sobald eine Anweisung nicht mehr einfach ist, da ein Tabellenformat nicht mehr beibehalten werden kann. Lange Codezeilen sind ein eigenständiger Geruch, es sei denn, Sie machen Code-Verschleierung. (Ursprünglich waren es 80 Zeichen, heutzutage sind es eher 130 Zeichen, aber nach dem allgemeinen Prinzip sollte man nicht scrollen müssen, um das Zeilenende zu sehen.)
Graham,
1

Das tabellarische Layout kann in einigen wenigen Fällen hilfreich sein, in einigen Fällen ist es jedoch hilfreich, wenn.

In einfachen Fällen?: Kann eine bessere Wahl sein. In mittleren Fällen passt ein Schalter oft besser (wenn Ihre Sprache einen hat). In komplizierten Fällen stellen Sie möglicherweise fest, dass Aufruftabellen besser passen.

Es gab viele Male, als ich Code umgestaltete, um es tabellarisch darzustellen, damit es offensichtlich wird. Es ist selten der Fall, dass ich es so lasse, da es in den meisten Fällen einen besseren Weg gibt, das Problem zu lösen, sobald Sie es verstanden haben. Gelegentlich verbietet eine Codierungspraxis oder ein Layoutstandard dies. In diesem Fall ist ein Kommentar hilfreich.

Es gab einige Fragen zu ?:. Ja, es ist der ternäre Operator (oder, wie ich finde, der Wert, wenn). Beim ersten Erröten ist dieses Beispiel ein wenig kompliziert für?: (und übermäßiges Verwenden?: hilft der Lesbarkeit nicht, schadet aber), aber mit einigem Nachdenken. Das Beispiel kann wie folgt umgestellt werden Lösung.

if i==0: return 0
return i>0?sqrt(i):(1j*sqrt(-i))
hildred
quelle
1
Möglicherweise müssen Sie klarstellen, was "?:" Für Uneingeweihte ist (zum Beispiel mit einem Beispiel, das möglicherweise mit der Frage zusammenhängt).
Peter Mortensen
Ich nehme an, das ist der ternäre Operator. Ich fühle mich gemieden aus dem guten Grund, dass der ternäre Operator dazu neigt, den Standard neu zu ordnen, wenn er Dinge tut oder andere Dinge formatiert, die die Leute Tag für Tag sehen und daher leicht lesen können.
Horta
@PeterMortensen: Wenn die Uneingeweihten nicht wissen, was dies bedeutet, sollten sie sich vom Code fernhalten, bis sie die offensichtliche Frage gestellt und gelernt haben.
Gnasher729
@ Horta Ternary ist if ? do stuff : do other stuff. Gleiche Reihenfolge wie bei if / else.
Navin
1
@Navin Ah, vielleicht ist es nur ein Fehler der Sprache, die ich am häufigsten verwende (Python). stackoverflow.com/questions/394809/…
horta
-3

Ich sehe nichts falsch mit dem Tabellenformat. Persönliche Präferenz, aber ich würde einen Ternären wie diesen verwenden:

return i>0  ? sqrt(i)       :
       i==0 ? 0             :
              1j * sqrt(-i)

Keine Notwendigkeit, returnjedes Mal zu wiederholen :)

Navin
quelle
1
Wie in einigen Kommentaren erwähnt, sind die return-Anweisungen nicht ideal oder der Punkt des Posts, sondern einfach ein Stück Code, den ich online gefunden und auf verschiedene Arten formatiert habe.
Horta
Python-Ternaries sind es do_something() if condition() else do_something_else()nicht condition() ? do_something() : do_something_else().
Isiah Meadows
@IsiahMeadows OP hat Python nie erwähnt.
Navin