Einrückungsstil
Als Einrückungsstil (engl. indent style) wird die Art und Weise bezeichnet, Quelltext von Programmen zur besseren Lesbarkeit einzurücken und umschließende Syntax-Elemente wie geschweifte Klammern {}
zu positionieren. Als alternativer Name ist daher auch manchmal „Klammerstil“ (engl. brace style) anzutreffen.
Für die Programmiersprache C gibt es vier verbreitete Einrückungsstile, die auch in Programmier- und Skriptsprachen mit C-ähnlicher Syntax wie C++, Java, JavaScript, Perl oder C# übernommen wurden. Für die Programmiersprache Python gibt es einen verbindlichen Einrückungsstil.
Die Positionierung der geschweiften Klammern ist wahrscheinlich das umstrittenste Element eines Programmierstils.
Elemente des Einrückungsstils
Der Einrückungsstil bezieht sich auf:
- Positionierung umschließender Syntax-Elemente, insbesondere
{}
und()
- Tiefe der Einrückung
- Verwendung von Leerzeichen vor
{
und(
- Verwendung von Tabulatorzeichen zur Einrückung.
Häufig wird empfohlen, einen Quelltext nicht so zu formatieren, dass die Einrückung erst mit einer Veränderung der Tabulatorschrittweite auf einen anderen Wert sichtbar wird, z. B. 4 statt 8 Zeichen. Viele Editoren verwenden als Voreinstellung für die Tabulatorschrittstellerücken den Wert von 8 Leerzeichen. Um die Abhängigkeit der Darstellung von der eingestellten Tabulatorschrittweite gänzlich zu vermeiden, raten die meisten Einrückungsstile von der Verwendung von Tabulatorzeichen grundsätzlich ab.
Positionierung umschließender Syntax-Elemente
Umschließende Syntax-Elemente sind solche Syntax-Elemente einer Sprache, die zur Gruppierung einer unbestimmten Zahl von Elementen dienen, nicht ausschließlich aber insbesondere dann, wenn sich die Elemente über mehrere Quelltextzeilen erstrecken. In Sprachen mit C-ähnlicher Syntax, z. B. C++, Java und C#, in Sprachen mit Pascal-ähnlicher Syntax, z. B. Modula-2, Oberon und Cluster sowie einigen weiteren Sprachen fällt diesen Elementen bei der Gestaltung eines Quelltextes in Bezug auf seine Syntax und seine Lesbarkeit eine zentrale Bedeutung zu.
Positionierung in Pascal
Pascal-ähnliche Sprachen verwenden zur Umschließung eigens dafür definierte Schlüsselwörter, meist BEGIN
, DO
und END
. In der Praxis wird eine Positionierung dieser Elemente nur selten diskutiert, meist wird sie so vorgenommen, wie von Niklaus Wirth in der Literatur vorgeführt. Dabei steht BEGIN
noch in der Einrückung des äußeren Blocks auf einer eigenen Zeile, DO
dagegen wird am Ende der vorherigen Zeile zusammen mit dem das DO
benötigenden Statement geschrieben. Der Inhalt des durch BEGIN
oder DO
eingeleiteten Blocks wird bis ausschließlich zum END
eingerückt. Das END
steht ausgerückt, d. h. in der Einrückung des äußeren Blocks schließlich wieder auf einer eigenen Zeile.
Beispiel: Positionierung der umschließenden Syntax-Elemente in Oberon
PROCEDURE Add(VAR x, y: INTEGER)
BEGIN
WHILE (y != 0) DO
y := y - 1;
x := x + 1;
END
END Add;
Positionierung in C
C-ähnliche Sprachen verwenden zur Umschließung ein Paar von geschweiften Klammern {
und }
. In der Praxis können diese Klammern nahezu beliebig positioniert werden, so dass sich mehrere verschiedene Stile entwickelt haben, von denen keiner als dominant zu bezeichnen ist.
Positionierung in XML- und SGML-basierten Sprachen
In XML- und SGML-basierten Sprachen, z. B. HTML, hat sich durchgesetzt, die Inhalte von Elementen zwischen Start-Tag und End-Tag einzurücken. Für Attribute findet man immer häufiger eine mehrzeilige Aufteilung, besonders, wenn Übersichtlichkeit gefragt ist.
Beispiel: Einrückung in einem XHTML-Quelltext
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de">
<head>
<title>Einrückung in XML</title>
</head>
<body>
<h1>Einrückung in XML</h1>
<p>
Dieses Dokument ist ein Beispiel für Einrückung in XML / SGML.
<br />
In diesem Beispiel beträgt die Einrückungstiefe 4 Leerzeichen.
</p>
</body>
</html>
Beispiel: Einrückung in einem Ant-Quelltext
<?xml version="1.0"?>
<!--
- Daimonin Editor build file
-->
<project
name = "Daimonin Editor"
default = "compile"
>
<target
name = "compile"
description = "compile Daimonin Editor"
>
<javac
srcdir = "src"
destdir = "classes"
encoding = "utf-8"
source = "1.5"
target = "1.5"
debug = "no"
/>
</target>
</project>
Einrückungstiefe
Die Einrückungstiefe bestimmt, wie weit der Inhalt eines Blocks eingerückt wird. Besonders weit verbreitet sind Einrückungstiefen um 4 oder 8 Leerzeichen, aber auch 2 oder 3 Leerzeichen sind nicht selten anzutreffen. Ein Experiment aus dem Jahr 1983 mit Pascal Code zeigt, dass die Einrückungstiefe einen signifikanten Einfluss auf die Verständlichkeit des Codes hat. Den Ergebnissen zufolge wird mit Einrückungstiefen im Bereich von 2 bis 4 Leerzeichen die beste Verständlichkeit erreicht.[1]
Sofern eine maximale Textbreite vorgegeben bzw. angestrebt wird, führt eine zu große Einrückungstiefe zu häufigeren Zeilenumbrüchen. Das ergibt sich durch die kürzere verbleibende Zeilenlänge nach der Einrückung, innerhalb derer längere Anweisungen oder Ausdrücke nicht mehr untergebracht werden können. Dieser Effekt trägt zur Abnahme der Lesbarkeit bei höheren Einrückungstiefen bei.[1] Die verbleibende Zeilenlänge lässt sich wie folgt berechnen: verbleibende Zeilenlänge = Textbreite − Schachtelungstiefe · Einrückungstiefe. Bei einer Textbreite von 79 Zeichen, einer Einrückungstiefe von 8 Leerzeichen und einer Schachtelungstiefe von 3 Ebenen beträgt die verbleibende Zeilenlänge also noch 55 Zeichen.
Beispiel: Java-Quelltext mit Einrückungstiefe 2 Leerzeichen
public class Hello {
public static void main(String... args) {
if (args.length > 0) {
for (String arg : args) {
System.out.println("Hello, " + arg + "!");
}
} else {
System.out.println("Hello, world!");
}
}
}
Beispiel: Java-Quelltext mit Einrückungstiefe 4 Leerzeichen
public class Hello {
public static void main(String... args) {
if (args.length > 0) {
for (String arg : args) {
System.out.println("Hello, " + arg + "!");
}
} else {
System.out.println("Hello, world!");
}
}
}
Beispiel: Java-Quelltext mit Einrückungstiefe 8 Leerzeichen
public class Hello {
public static void main(String... args) {
if (args.length > 0) {
for (String arg : args) {
System.out.println("Hello, " + arg + "!");
}
} else {
System.out.println("Hello, world!");
}
}
}
Wie man sieht, werden mit wachsender Einrückungstiefe die Zeilen länger, was bei einer begrenzten Textbreite weniger Platz für Anweisungen und Ausdrücke innerhalb einer Zeile lässt.
Verwendung von Tabulatorzeichen oder Leerzeichen
Die Einrückung eines Quelltextes lässt sich in den meisten Programmiersprachen wahlweise mit Leerzeichen oder mit Tabulatorzeichen vornehmen. Die meisten Compiler sehen darin keinen Unterschied, die Wahl bleibt also dem Programmierer überlassen.
Es gibt jedoch Argumente, die für oder gegen eine Einrückung mit Leerzeichen bzw. Tabulatorzeichen sprechen. Für eine Einrückung mit Leerzeichen spricht, dass die Einrückungstiefe grundsätzlich gleich bleibt und die Einrückung so stets erkennbar ist, unabhängig davon, welche Tabulatorschrittweite verwendet wird. Für eine Einrückung mit Tabulatorzeichen spricht, dass sich jeder Entwickler selbst die Tabulatorschrittweite einstellen und somit seine persönliche Einrückungstiefe bestimmen kann.
Wichtiger als die Wahl des Einrückungsstils ist es, den gewählten Stil konsequent einzuhalten, da eine Mischung zu Problemen bei der Darstellung führen kann.
Beispiel: Quelltext mit gemischter Einrückung (sowohl Tabulatorzeichen als auch Leerzeichen), der mit einer Tabulatorschrittweite von 4 erstellt und 8 angezeigt wurde (Darstellung der Leerzeichen durch Punkte, der Tabulatorzeichen durch Pfeile).
public class Hello {
→ public static void main(String... args) {
........if (args.length > 0) {
............for (String arg : args) {
→ ............System.out.println("Hello, " + arg + "!");
}
→ → } else {
............System.out.println("Hello, world!");
........}
→ }
}
Die Darstellung könnte durch eine Umstellung der Tabulatorschrittweite korrigiert werden. Für einige wenige Editoren, z. B. vim, lassen sich in den Quelltexten Steuerinformationen unterbringen, die den Editor automatisch auf die verwendete Tabulatorschrittweite stellen. Diese Editoren stellen jedoch die Ausnahme dar, außerdem mangelt es an einem einheitlichen Standard für solche Einstellungen. Ohne diese Möglichkeiten muss der Programmierer bei gemischten Quelltexten jeden Quelltext optisch betrachten, die Tabulatorschrittweite erraten und entsprechend neu einstellen.
Bekannte Einrückungsstile
Hinweis zu den Beispielen
Die Code-Beispiele dienen dazu, den Einrückungsstil zu demonstrieren. Ihr Inhalt ist kaum sinnvoll.
1TBS / K&R / Kernel / Linux / UNIX / Stroustrup / Java / Sun
Beispiel: GNU-Beispiel in 1TBS
if (x < foo(y, z)) {
qux = bar[4] + 5;
} else {
while (z) {
qux += foo(z, z);
z--;
}
return ++x + bar();
}
Der Name 1TBS (auch OTBS) kommt aus dem Hacker-Jargon und steht für „One True Brace Style“, was übersetzt soviel bedeutet wie „einzig wahrer Klammern-Stil“. Der Name bezieht sich darauf, dass dieser Stil von den C-Erfindern Brian W. Kernighan und Dennis Ritchie definiert wurde.
Die Positionierung der öffnenden Klammern am Zeilenende ist gleichermaßen beliebt wie verhasst. Mit schlechten Entwicklungswerkzeugen besteht bei Unachtsamkeit die Gefahr, öffnende Klammern zu übersehen und schließende zu vergessen.
Andererseits bietet dieser Stil zwei Vorteile:
- Wesentlich mehr Code wird in der gleichen Zahl Zeilen dargestellt.
- Unselbstständige Folgeblöcke werden an der schließenden geschweiften Klammer unter einer schließenden geschweiften Klammer in derselben Spalte erkannt.
Die überwiegende Mehrheit der Java- und ECMAScript-Programmierer verwendet diesen Stil. Auch Perl-Programmierer verwenden meist 1TBS, weil sie es sowieso bevorzugen, ihre Programme möglichst kurz zu halten.
C-Code verwendete früher 8 Leerzeichen pro Einrückungsschritt, heute sind auch manchmal 4 oder 3 Leerzeichen anzutreffen. Bei Java ist eine Einrückung um 4 Leerzeichen die Regel.
Variation: Original K&R / Kernel / Linux / UNIX / Stroustrup
Beispiel: GNU-Beispiel in K&R
int f(int x, int y, int z)
{
if (x < foo(y, z)) {
qux = bar[4] + 5;
} else {
while (z) {
qux += foo(z, z);
z--;
}
return ++x + bar();
}
}
Dieser Programmierstil wurde von den C-Erfindern Brian W. Kernighan und Dennis Ritchie (K&R) in ihrem Buch The C Programming Language (Deutscher Titel: Programmieren in C) sowie zusammen mit Ken Thompson bei der Entwicklung von UNIX und seines Kernels verwendet. Auch die Code Conventions von Linus Torvalds für Linux schlagen diesen Stil vor.
Die dargestellte Einrückungstiefe ist die beim Linux-Kernel verwendete. Die Einrückung untergeordneter Syntaxelemente beträgt dort 8 Leerzeichen. Dies erleichtere die Lesbarkeit auch nach 20-stündiger Bildschirmarbeit. Von einer Einrückung von mehr als 3 Ebenen wird abgeraten und stattdessen eine Umstrukturierung des Quelltextes vorgeschlagen.[2]
Im Gegensatz zum durchgängigen Einsatz des 1TBS, wie z. B. beim Java-Stil, wird bei der Definition von Funktionen auf den Allman-Stil zurückgegriffen.
Die Ausnahmeregelung für die Funktionen in C findet mehrere Begründungen:
- K&R verwenden ebenfalls exakt diese Positionierung der Klammern
- Sie erlaubt es, in einem Editor ohne Parser für die jeweilige Sprache von Funktion zu Funktion zu springen (z. B. im vi mittels
[[</code> bzw. <code>]]
). - Die Ausnahmeregelung bietet eine besonders hohe Lesbarkeit bei umbrochenen Funktionsdefinitionen:
static int
kwrite_args(struct posix_log_entry *rec_hdr, va_list args,
unsigned char **pvardata)
{
// ...
}
- Historisch gesehen war sie keine "Optimierung", sondern eine Notwendigkeit, die aus der Funktionsdefinitions-Syntax von K&R (d. h. pre-ANSI) C-Code hervorging, dort trennt die öffnende geschweifte Klammer die Typenliste der Funktionsparameter vom Funktionskörper:
int foo(a, p)
int a;
char *p;
{
/* ... */
}
Wird dieser Stil auf C++ angewandt, nennt man ihn auch Stroustrup nach dem Erfinder von C++, welcher den K&R-Stil um Elemente für C++ erweitert hat. Für alle neuen Elemente, z. B. Klassen, werden öffnende geschweifte Klammern ans Ende einer Zeile gestellt:
class C : public B {
public:
// ...
};
Variation: Java / Sun
Beispiel: GNU-Beispiel in Java-Stil
int f(int x, int y, int z) {
if (x < foo(y, z)) {
qux = bar[4] + 5;
} else {
while (z) {
qux += foo(z, z);
z--;
}
return ++x + bar();
}
}
Dieser Stil wird von Sun für die Programmiersprache Java empfohlen.[3] Auch bei C++ ist dieser Stil häufig anzutreffen. Auf die Ausnahmeregelung, die geschweiften Klammern von Methoden (= objektorientierte Funktion) gemäß Allman zu positionieren, wird verzichtet, da Methoden als Elemente von Klassen geschachtelt sind.
Aufgrund der häufiger auftretenden Schachtelung wird eine Einrückung um 4 statt 8 Leerzeichen bevorzugt.
Allman / BSD
Beispiel: GNU-Beispiel in Allman-Stil
int f(int x, int y, int z)
{
if (x < foo(y, z))
{
qux = bar[4] + 5;
}
else
{
while (z)
{
qux += foo(z, z);
z--;
}
return ++x + bar();
}
}
Dieser Stil wurde nach Eric Allman benannt, der eine Vielzahl an BSD-Werkzeugen geschrieben hat, weshalb dieser Stil auch nicht ganz korrekt BSD-Stil heißt. Da er die Grundeinstellung der Entwicklungsumgebung Visual Studio von Microsoft ist, hat er in der Programmierung für Windows eine große Verbreitung.
Der Vorteil des Allman-Stils ist, dass sich die Blockbereiche gut erkennen lassen, was besonders bei höheren Verschachtelungstiefen hilfreich ist.
Als nachteilig wird von manchen Programmierern angesehen, dass dieser Stil einen hohen Zeilenverbrauch hat. Pro Block wird eine zusätzliche Zeile im Vergleich mit 1TBS benötigt. In C, C++ und Sprachen mit vergleichbaren Präprozessoren gibt es jedoch Situationen, in denen dieser Stil auch wesentliche Vorteile gegenüber 1TBS zeigt, und zwar beim Einsatz von bedingter Kompilierung für alternative Blockeinleitungen.
Beispiel: Vorteil des Allman-Stils bei bedingter Kompilierung von Blockeinleitungen
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
// ...
}
Die Zahl der Klammern insgesamt bleibt auch beim Einsatz bedingter Kompilierung gleich, was wichtig für die korrekte Zuordnung von öffnenden und schließenden Klammern in Texteditoren mit entsprechender Funktionalität ist.
Hinweis: Dieser Stil wird zwar häufig BSD-Stil genannt, für den BSD-Kernel wird jedoch wie für UNIX und Linux 1TBS verwendet, wie in den Style-Manpages der verschiedenen BSD-Derivate nachzulesen ist.[4][5]
Horstmann
Der Horstmann-Stil ist eine Abwandlung des Allman-Stils, bei dem die erste Anweisung nach der öffnenden geschweiften Klammer direkt in derselben Zeile geschrieben wird. Der Code von oben sieht dann so aus:
int f(int x, int y, int z)
{ if (x < foo(y, z))
{ qux = bar[4] + 5;
}
else
{ while (z)
{ qux += foo(z, z);
z--;
}
return ++x + bar();
}
}
Für VCS-Tools ist dieser Stil problematisch. Fügt man eine neue Anweisung zwischen dem "{" und der vormals ersten Anweisung ein, erscheint diese Änderung als „eine Zeile wird durch 2 Zeilen ersetzt“ statt „eine neue Zeile wurde eingefügt“. Das heißt, die ursprüngliche Zeile wird als „geändert“ markiert, obwohl sie semantisch gleich geblieben ist.
Whitesmith-Stil
Der Whitesmith-Stil wurde ursprünglich in der Dokumentation des ersten kommerziellen C-Compilers eingesetzt. Dieser Stil war in frühen Windows-Programmierhandbüchern populär, unter anderem im Programmer’s Guide to Windows (Durant, Carlson & Yao), in Programming Windows (Petzold) sowie Windows 3.0 Power Programming Techniques (Norton & Yao).
int f(int x, int y, int z)
{
if (x < foo(y, z))
{
qux = bar[4] + 5;
}
else
{
while (z)
{
qux += foo(z, z);
z--;
}
return ++x + bar();
}
}
Der Vorteil dieses Stils ist, dass der Block sich klar von der Kontrollanweisung absetzt und im Gegensatz zum Allman-Stil nicht den Lesefluss des Blocks unterbricht.
GNU-Stil
Beispiel: Original GNU-Beispiel
int f (int x, int y, int z)
{
if (x < foo (y, z))
qux = bar[4] + 5;
else
{
while (z)
{
qux += foo (z, z);
z--;
}
return ++x + bar ();
}
}
Dieser Programmierstil ist vor allem in GNU-Projekten der Free Software Foundation zu finden und wird von ihr empfohlen. Außerhalb der Free Software Foundation ist er eher selten anzutreffen und auch innerhalb der Free Software Foundation wird er nicht von allen verwendet.
Das genannte Beispiel wurde den GNU Coding Standards entnommen.[6] Die anderen Beispiele sind in Bezug auf Einrückung und Klammernsetzung umformatiert.
Verfechter des GNU-Stils beschreiben ihn deshalb als besonders leserlich, weil den geschweiften Klammern in der Positionierung und Einrückung eine eigene Ebene zukommt. Gegner hingegen argumentieren, dass dadurch ein gewisses Chaos bei der Quelltextformatierung entstehe; die Lesbarkeit und konsequente Einrückung würden erschwert.
Ratliff Stil
In dem Buch "Programmers at Work" besprach Wayne Ratliff den unten gezeigten Stil. Er beginnt ähnlich wie 1TBS, aber die Einrückung der schließenden Klammer stimmt mit der des geschachtelten Blocks überein. Dieser Stil wird manchmal als Bannerstil bezeichnet, wohl wegen der Ähnlichkeit mit einem Banner, das an einer Stange hängt. Der Stil kann das visuelle Erfassen vereinfachen, da nur die Header eines Blocks auf dieser Ebene nach links hervortreten.
// In C
for (i = 0; i < 10; i++) {
if (i % 2 == 0) {
doSomething(i);
}
else {
doSomethingElse(i);
}
}
oder, in einer Auszeichnungssprache...
<table>
<tr>
<td> lots of stuff...
more stuff
</td>
<td> alternative for short lines </td>
<td> etc. </td>
</tr>
</table>
<table>
<tr> ... etc
</table>
Weblinks
- Jargon über Einrückungsstile (englisch)
- Code Conventions for the Java Programming Language (englisch)
- The GNU Coding Standards (englisch)
- Erörterung der Vor- und Nachteile von Tabulator- oder Leerzeichen bei der Einrückung (englisch)
- Object Pascal Style Guide (englisch)
- C++ Coding Standard von Todd Hoff (englisch)
- Coding Standard des Zend Framework (PHP)