Warum sollte eine Sprache Einrückungen gegenüber expliziten Markierungen für Blöcke bevorzugen?

11

Ich lerne Haskell und suchte nach einem Tool zum automatischen Einrücken. Ich sah nicht viel aus und erfuhr, dass Einrückung in Haskell (wie in Python) einen Block bedeutet. Daher schätze ich, dass es unmöglich ist, ein Tool zur automatischen Formatierung zu erstellen, das so stark ist wie in anderen Sprachen der C-Familie und explizite Markierungen wie {} (geschweifte Klammern) oder begin endSchlüsselwörter verwendet.

Es macht mir nichts aus, wenn eine Sprache die Einrückung für die Lesbarkeit erzwingt, aber ich kann die Vorteile gegenüber der Erzwingung der Einrückung und einer expliziten Markierung nicht verstehen, damit automatisierte Tools verstehen können, was zu welchem ​​Block gehört.

Wenn die Präferenz der Einrückung beim Markieren eines Blocks darin besteht, dass der Code besser aussieht , verstehe ich den Vorteil immer noch nicht. Angesichts der Tatsache, dass Tabulatoren und Leerzeichen in verschiedenen Editoren und Schriftarten unterschiedlich dargestellt werden (Mono-Space-Schriftarten sehen beispielsweise aufgeräumter aus), ist es unmöglich zu erwarten, dass der Programmierer den Code anständig präsentiert. Ein Tool, das den aktuellen Texteditor berücksichtigen kann, ist viel besser geeignet, um den Code korrekt zu formatieren.

Warum sollte ein Sprachdesigner Einrückungen anstelle expliziter Blockmarkierungen wählen?

Stellen Sie Monica wieder her
quelle
8
Keine Antwort, aber Haskell macht die Empfindlichkeit von Leerzeichen viel optionaler als Python. Sie können für die meisten Dinge Semikolons verwenden und Blöcke bei Bedarf in geschweifte Klammern setzen. let x =1; y = 2; z = 3ist so wie es ist völlig gültig do { putStrLn $ show x; putStrLn $ show y; putStrLn $ show z; }. Diese müssen nicht in derselben Zeile stehen.
KChaloux
8
"Es ist unmöglich, ein automatisches Formatierungswerkzeug zu erstellen" - tatsächlich ist ein solches automatisches Formatierungswerkzeug in Python aufgrund der Einrückungsregeln nicht erforderlich.
Doc Brown
13
Ähm, zunehmende Einrückung ist eine explizite Blockmarkierung.
Karl Bielefeldt
3
@ K.Gkinis: Die beste Quelle für die genauen Motivationen hinter einer Sprachentwurfsentscheidung sind die Sprachdesigner selbst.
Robert Harvey
3
Diese Frage ist eigentlich nicht subjektiv. Es wird gefragt, warum einige Sprachdesigner eine bestimmte Syntax gewählt haben. Dies kann beantwortet werden. Wenn die Frage gestellt hätte, welche Syntax am besten ist , wäre sie subjektiv.
JacquesB

Antworten:

13

Guido Von Rossum

Aus einem Interview mit Guido Van Rossum , das im Volltext mit books.google.com (Schwerpunkt Mine) zu sehen ist:

Die Wahl der Einrückung für die Gruppierung war in Python kein neuartiges Konzept. Ich habe dies von ABC geerbt , aber es kam auch in Occam vor, einer älteren Sprache. Ich weiß nicht, ob die ABC-Autoren die Idee von Occam haben oder sie unabhängig erfunden haben oder ob es einen gemeinsamen Vorfahren gab. Natürlich hätte ich mich dafür entscheiden können, ABCs Vorbild nicht zu folgen, wie ich es in anderen Bereichen getan habe (z. B. verwendete ABC Großbuchstaben für Sprachschlüsselwörter und Prozedurnamen, eine Idee, die ich nicht kopiert habe), aber mir gefiel die Funktion ziemlich gut Während der Verwendung von ABC schien dies eine bestimmte Art von sinnloser Debatte zu beseitigen, die zu dieser Zeit unter C- Benutzern üblich war, wo die geschweiften Klammern platziert werden sollten .

Von Rossum war stark von ABC inspiriert , und obwohl er nicht alles kopieren musste, wurde die Verwendung von Einrückungen beibehalten, da dies zur Vermeidung von Religionskriegen von Vorteil sein könnte.

Mir war auch bewusst, dass lesbarer Code Einrückungen freiwillig verwendet , um eine Gruppierung anzuzeigen, und ich hatte subtile Fehler im Code festgestellt, bei denen die Einrückung nicht mit der syntaktischen Gruppierung in geschweiften Klammern übereinstimmte - der Programmierer und alle Prüfer hatten angenommen, dass die Einrückung mit der Gruppierung übereinstimmte und deshalb den Fehler nicht bemerkt. Wiederum lehrte eine lange Debugging-Sitzung eine wertvolle Lektion.

Rossum sah auch Fehler aufgrund von Inkonsistenzen zwischen Gruppierung und Einzug, und anscheinend wäre es sicherer, wenn man sich nur auf Einrückungen stützt, um den Code zu strukturieren, vor Programmierfehlern 1 .

Donald E. Knuth und Peter J. Landin

In dem Interview, auf das verwiesen wird, erwähnt Guido Don Knuths Idee, Einrückungen zu verwenden. Dies wird in The Knuth Indentation Quote (Wiederentdeckung des Knuth-Einrückungszitats) beschrieben , in dem die strukturierte Programmierung mit goto-Anweisungen zitiert wird . Knuth verweist auch auf Peter John Landins Die nächsten 700 Programmiersprachen (siehe Abschnitt Diskussion über Einrückungen). Landin hat ISWIM entworfen, das wie die erste Sprache mit Einrückung anstelle von Start- / Endblöcken aussieht. In diesen Papieren geht es eher um die Machbarkeit der Verwendung von Einrückungen zur Strukturierung von Programmen als um tatsächliche Argumente dafür.


1. Ich denke, dass dies in der Tat ein Argument für Gruppierungskonstrukte und automatische Formatierung ist, um Programmierfehler zu erkennen und zu beheben, die zwangsläufig auftreten werden. Wenn Sie Ihre Einrückung in Python vermasseln, muss die Person, die Ihren Code debuggt, raten, welche richtig ist:

if (test(x)):
  foo(x)
  bar(x)

Soll barimmer aufgerufen werden oder nur wenn der Test erfolgreich ist?

Gruppierungskonstrukte fügen eine Redundanzstufe hinzu, mit der Sie einen Fehler erkennen können, wenn Sie Ihren Code automatisch einrücken. In C kann der entsprechende Code wie folgt automatisch eingerückt werden:

if (test(x))
  foo(x);
bar(x);

Wenn ich beabsichtigte bar, auf dem gleichen Niveau wie zu sein foo, kann ich durch automatisches Einrücken basierend auf der Codestruktur feststellen, dass etwas nicht stimmt, das durch Hinzufügen von geschweiften Klammern um foound behoben werden kann bar.

In Python: Mythen über Einrückung gibt es ein angeblich schlechtes Beispiel aus C:

/*  Warning:  bogus C code!  */

if (some condition)
        if (another condition)
                do_something(fancy);
else
        this_sucks(badluck);

Das ist der gleiche Fall wie oben. In Emacs hebe ich den gesamten Block / die gesamte Funktion hervor, drücke die Tabulatortaste und dann wird der gesamte Code neu eingerückt. Die Diskrepanz zwischen menschlicher Einrückung und Codestruktur sagt mir, dass etwas nicht stimmt (das und der vorhergehende Kommentar!).

Außerdem schafft es der Zwischencode, bei dem die Einrückung in C deaktiviert ist, einfach nicht durch den Hauptzweig. Alle vorhandenen Stilprüfungen würden GCC / Jenkins dazu bringen, mich anzuschreien. Ich hatte kürzlich ein ähnliches Problem wie das oben in Python beschriebene, mit einer Aussage, die durch eine Einrückungsstufe abweicht. Manchmal habe ich Code in C, der über eine schließende Klammer hinausgeht, aber dann drücke ich die Tabulatortaste und der Code wird "falsch" eingerückt: Das ist eine weitere Chance, den Fehler zu sehen.

Core-Dump
quelle
3
"Um Religionskriege zu vermeiden ..." Ich bin überrascht, dass der wahre Grund so trivial ist.
Robert Harvey
1
@ RobertHarvey: Die Betonung dieses Satzes liegt bei Coredump, nicht bei van Rossum. Es ist nicht der Hauptgrund, wenn Sie das Zitat von van Rossum im Kontext lesen.
JacquesB
@JacquesB Bitte sagen Sie mir, welcher Kontext im Zitat fehlt, damit ich die Antwort bearbeiten kann.
Coredump
4
Ich verstehe Ihren persönlichen Kommentar jedoch nicht: Wenn Sie Einrückungen in Python vermasseln, haben Sie einen Fehler. Wenn Sie Klammern in C vermasseln, haben Sie einen Fehler. Wenn Sie das automatische Einrücken verwenden, ist es in beiden Sprachen genau gleich. Und wenn Sie kein automatisches Einrücken verwenden, kann der Fehler in C auf eine Weise versteckt werden, die in Python nicht möglich ist.
JacquesB
2
@JacquesB, weil Sie aktiv eine schließende Klammer eingeben; Nicht genug Einrücken ist etwas, das Sie vergessen können. Natürlich können Sie vergessen, eine Zahnspange zum richtigen Zeitpunkt zu schließen, aber Sie müssen es irgendwann tun und eine weitere Chance bekommen, darüber nachzudenken. Ich denke, Python funktioniert gut für Anfänger, weil es die Aufmerksamkeit auf Einrückungen lenkt.
Marstato
7

Dies ist sehr subjektiv und die Ursache für viele Flammenkriege. Jedoch:

Symbole, die Blöcke und Einrückungen begrenzen, verstoßen gegen das DRY-Prinzip , da Sie dieselben Informationen auf zwei verschiedene Arten ausdrücken. Das Vorhandensein automatisierter Einrückungswerkzeuge ist ein Symptom für diese DRY-Verletzung: Dass Sie die Einrückung automatisch generieren können, zeigt, dass es sich um redundante Informationen handelt. Dies bedeutet, dass die Einrückung und die Symbole möglicherweise nicht mehr synchron sind, was zu irreführendem Code führt.

In den häufig gestellten Fragen zu Python- Design und -Geschichte wird dies sehr deutlich angegeben:

Warum verwendet Python Einrückungen zum Gruppieren von Anweisungen?

Guido van Rossum ist der Ansicht, dass die Verwendung von Einrückungen für die Gruppierung äußerst elegant ist und viel zur Klarheit eines durchschnittlichen Python-Programms beiträgt. Die meisten Menschen lernen diese Funktion nach einer Weile zu lieben.

Da es keine Anfangs- / Endklammern gibt, kann es keine Meinungsverschiedenheiten zwischen der vom Parser und dem menschlichen Leser wahrgenommenen Gruppierung geben.

Es ist richtig, dass Sie kein Tool zum automatischen Einrücken für Python erstellen können, aber das ist gut so: Es bedeutet, dass Sie keine Redundanzen in der Syntax haben, für deren Abgleich Sie automatisierte Tools benötigen.

Die Tabulatoren gegen Leerzeichen sind in Python ein berechtigtes Problem, und es wird empfohlen, Tabulatoren und Leerzeichen (zum Einrücken) niemals in derselben Codebasis zu mischen.

Python erbte die signifikante Einrückung von der (inzwischen veralteten) Vorgängersprache ABC. ABC ist eine der wenigen Programmiersprachen, die Usability-Tests verwendet haben , um das Design zu steuern. Während Diskussionen über die Syntax normalerweise auf subjektiven Meinungen und persönlichen Vorlieben beruhen, hat die Wahl einer signifikanten Einrückung tatsächlich eine fundiertere Grundlage.

JacquesB
quelle
6
Die doppelte Buchführung verstößt ebenfalls gegen DRY. Redundanz ist manchmal ein Merkmal.
Coredump
3
@coredump: Stimmt, aber es ist eine bewusst gestaltete Redundanz. Die meisten Programmiersprachen, einschließlich Python, enthalten absichtlich ausgewählte Redundanzen - z. B. das passSchlüsselwort, das automatisch abgeleitet werden kann, dessen explizite Angabe jedoch dazu beiträgt, Fehler zu entdecken. Die versehentliche Redundanz, sowohl Start- / Endsymbole (für den Compiler) als auch Einrückungen (für den menschlichen Leser) zu haben, scheint mehr Fehler zu verursachen, als sie abfangen. Zumindest scheint dies die Ansicht von van Rossum zu sein.
JacquesB
@coredump - Jetzt weiß ich, warum ich kein Buchhalter bin.
JeffO
3
@coredump Du vermisst auch COBOL's PROCEDURE DIVISION.? Ich kann nie sagen, wo die DATA DIVISIONEnden und die Prozeduren in diesen neuen Sprachen beginnen.
Msw
2
@coredump: "Einrückungen zu sehen, die meinen Vorstellungen widersprechen, reicht aus, um Fehler zu vermeiden" - genau.
JacquesB
2

Sprachdesigner wählen syntaktisch signifikante Leerzeichen, weil sie glauben (oder zumindest glauben, dass ihre potenziellen Benutzer glauben), dass die Semikolons und Klammern beim Lesen von Code Rauschen verursachen und die Produktivität beeinträchtigen. Ein weiterer häufiger Grund ist, dass ein schlechter / inkonsistenter Codierungsstil die Lesbarkeit beeinträchtigt. Durch Erzwingen eines gemeinsamen Einrückungsschemas ist die Lesbarkeit insgesamt besser. Dieser spätere Grund ist jetzt weniger wichtig, da IDEs mit automatischer Formatierung häufiger vorkommen, aber dennoch angewendet werden können.

Telastyn
quelle
1
Ich kann sehen, warum man Semikolons und geschweiftes Klammerrauschen in Betracht ziehen würde. Aber ist es nicht weniger produktiv, 4/8/12 mal Leerzeichen eingeben zu müssen? Und wenn Sie eine verpassen (da sie unsichtbar sind), sind Sie in Schwierigkeiten.
Stellen Sie Monica
5
Aus diesem Grund verwenden Sie Tabulatoren anstelle von Leerzeichen oder eine IDE, die versteht, wie Tabulatoren in Blöcke mit vier Leerzeichen konvertiert werden.
Robert Harvey
@ K.Gkinis: Einrückungen sind nicht unsichtbar. Nur Leerzeichen am Zeilenende sind unsichtbar, dies ist jedoch in keiner Sprache von Bedeutung. Nur wenn Sie Tabulatoren und Leerzeichen mischen, geraten Sie in Schwierigkeiten. Also tu das nicht.
JacquesB
@JacquesB: Das Problem mit der Sichtbarkeit / Unsichtbarkeit von Einrückungen ist, dass man als Mensch oft nicht den Unterschied zwischen Leerzeichen und Tabulatoren erkennen kann, während der Computer dies kann und oft tut. Während die Einrückung sichtbar ist, kann die Art und Weise, wie der Computer die Einrückung interpretiert, unterschiedlich sein. Das ist das eigentliche Problem: Wenn der Computer die unsichtbaren Zeichen anders behandelt als Menschen. Menschen messen Einrückungen als Entfernung auf einem Bildschirm, Computer können sie als wörtliche Anzahl von Zeichen messen. Das ist der unsichtbare Teil.
Bryan Oakley
@BryanOakley: Ja, deshalb sollten Sie Tabulatoren und Leerzeichen nicht in Einrückungen mischen.
JacquesB