Stand: 2018-08-24

T mit etwas Rum

Namen von Typparametern mit einem Zeichen sind nicht aussagekräftig. Aber was ist eine sinnvolle Konvention für Typparameter?

In zahlreichen Programmiersprachen wie zum Beispiel Java herrscht die Konvention, Typparameter mit nur einem Zeichen wie T zu benennen. Aber solche Namen transportieren sehr wenig Information und wenn es mehr als einen Typparameter gibt, kommt der Ansatz schnell an seine Grenzen.

Für einfache Datenstrukturen oder Methoden wird oft T verwendet, was als Platzhalter für “irgendeinen Typ” in Ordnung ist, wenn es wirklich irgendein Typ ist und es nur einen Typparameter gibt. Ein Beispiel dafür ist List<T>, denn Listen können einen beliebigen Typ enthalten. Aber schon ab dem zweiten Typparameter ergibt es keinen Sinn mehr, den ersten T wie “Typ” zu nennen.

Bestehende Konventionen

Welche Konventionen gibt es in verschiedenen Programmiersprachen und was sind ihre Vor- und Nachteile?

Java

Der gängigste Name für einen einen Typparameter ist in Java T als Platzhalter für irgendeinen Typ. Aber es gibt auch ein paar wenige Buchstaben, die als Abkürzung für ein bedeutungsvolles Wort stehen. Im Fall einer Map heißen die Typparameter zum Beispiel K wie “Key” und V wie “Value”. Verwendet werden außerdem noch E für “Element” und N für “Number”. Eigenartig wird es, wenn keines dieser einigermaßen beschreibenden Kürzel passt, denn dann wird nach T laut den Oracle Namenskonventionen einfach das Alphabet mit S, U, V und so weiter fortgesetzt (im Oracle-Alphabet kommt S nach T!).

Auszug aus Oracles Java Tutorial:

By convention, type parameter names are single, uppercase letters. This stands in sharp contrast to the variable naming conventions that you already know about, and with good reason: Without this convention, it would be difficult to tell the difference between a type variable and an ordinary class or interface name.

The most commonly used type parameter names are:

  • E - Element (used extensively by the Java Collections Framework)
  • K - Key
  • N - Number
  • T - Type
  • V - Value
  • S,U,V etc. - 2nd, 3rd, 4th types

Das Problem ist, dass bei der alphabetischen Fortsetzung nach T jede Bedeutung verloren geht. Das T kommt vermutlich aus der Anfangszeit, als generische Datentypen in erster Linie für Collections verwendet wurden und es da einfach ein Platzhalter für einen beliebigen Typ war.

Merkwürdig an dieser Konvention ist auch, dass Namen ohne jede konkrete Bedeutung wie T, S, U, und Namen mit einer Bedeutung, wie K für Key oder V für Value vorkommen. Was macht man, wenn man einen Typparameter E mit der Bedeutung Element verwendet und dann noch einen weiteren Typparameter hat, der ebenfalls E heißen müsste, weil er für etwas steht, das mit “E” beginnt?

Scala

In Scala gibt es die Konvention, einzelne Großbuchstaben beginnend bei A zu verwenden:

For simple type parameters, a single upper-case letter (from the English alphabet) should be used, starting with A (this is different than the Java convention of starting with T).

Diese Buchstaben transportieren bei Scala also prinzipiell keine Bedeutung, aber immerhin ist das Schema konsistent. A, B, C ist Scalas Entsprechung von Javas T, S, U für irgendwelche Typen. Für Typparameter mit einer konkreten Bedeutung werden dagegen sprechende Namen empfohlen:

If the type parameter has a more specific meaning, a descriptive name should be used, following the class naming conventions (as opposed to an all-uppercase style):

class Map[Key, Value]

Wenn der Gültigkeitsbereich eines Typparameters klein genug ist, sollen allerdings auch bei Scala einzelne Buchstaben als Gedächtnisstütze genügen:

If the scope of the type parameter is small enough, a mnemonic can be used in place of a longer, descriptive name:

class Map[K, V]

Damit kommt Scala auf insgesamt drei offizielle Ansätze zur Benennung von Typparametern. In der Praxis kommt noch die Java-Konvention bzw. eine Abwandlung davon hinzu, wie ein Blick in die Standardbibliothek zeigt:

Function2[T1, T2, R]
Tuple1[T1]
Awaitable[T] 

C#

Microsoft empfiehlt für C# sprechende, mit T beginnende, Namen, wenn einzelne Buchstaben nicht komplett selbsterklärend sind:

Do name generic type parameters with descriptive names, unless a single letter name is completely self explanatory and a descriptive name would not add value.

public interface ISessionChannel<TSession> { … }

public delegate TOutput Converter<TInput,TOutput>(TInput from);

public class List<T> { … }

Wenn es nur einen Typparameter gibt, reicht laut Microsoft T:

Consider using T as the type parameter name for types with one single letter type parameter.

public int IComparer<T> { … }   

public delegate bool Predicate<T>(T item);

public struct Nullable<T> where T:struct { … }

Die sprechenden Namen gefallen mir, das vorangestellte T finde ich dagegen etwas unschön. Es hat zwar in meinen Augen eine größere Existenzberechtigung als das I bei Schnittstellen, aber die Philosophie dahinter ist dieselbe, nämlich Metainformationen im Namen zu kodieren. Nach dem gleichen Prinzip könnte man alle Variablen vom Typ Integer mit i beginnen lassen …

Swift

Auch Swift bevorzugt im Normalfall sprechende Namen, die mit einem Großbuchstaben beginnen sollen:

In most cases, type parameters have descriptive names, such as Key and Value in Dictionary and Element in Array, which tells the reader about the relationship between the type parameter and the generic type or function it’s used in.

Wenn die Typparameter dagegen keine besondere Bedeutung haben, fällt Swift ausgerechnet auf die Namenskonventionen von Java zurück (abgesehen davon, dass S nicht vorkommt).

However, when there isn’t a meaningful relationship between them, it’s traditional to name them using single letters such as T, U, and V, such as T in the swapTwoValues(_:_:) function above.

Wohl kaum jemand würde ernsthaft in einer Code-Konvention empfehlen, dass Variablennamen immer nur aus einem einzigen Buchstaben bestehen sollten. Aus gutem Grund werden Variablen, Parameter und Klassen mit beschreibenden Namen benannt.

Was tun?

Dass Typparameternamen mit nur einem Zeichen in vielen Fällen keine gute Lösung sind, ist hoffentlich deutlich geworden. Meiner Meinung nach eignet sich dieser Ansatz nur in Fällen mit nur einem Parameter, der noch dazu völlig unspezifisch ist. Beispiele dafür sind Datenstrukturen, die beliebige Typen aufnehmen können: List<T>, Set<T>, Stack<T> und so weiter.

Sobald ein zweiter Typparameter dazu kommt, gibt es etwas, das diese beiden Parameter unterscheidet, und genau das sollte im Namen beschrieben werden. Ein gutes Beispiel dafür ist eine Map<Key, Value>.

Bei einer so gängigen Datenstruktur wie einer Map wird sich vermutlich fast jeder auch etwas unter der Abkürzung Map<K, V> vorstellen können. Aber wo soll man da eine Grenze ziehen? Was für den einen noch selbstverständlich ist, ist für den anderen ein bedeutungsloser Buchstabe! Bei der Benennung von Variablen wurde früher auch mit Zeichen gespart, was die Lesbarkeit stark beeinträchtigt hat. Heute, wo Buchstaben nicht mehr ganz so teuer sind, hat sich die Erkenntnis durchgesetzt, dass ein beschreibender Name das Verständnis des Codes sehr erleichtern kann. Warum sollte man also ausgerechnet bei Typparametern ein paar Zeichen sparen?

Oracle befürchtet, dass mit Namen, die länger als ein Zeichen sind, Verwechslungsgefahr mit Klassen oder Schnittstellen bestehen würde:

Without this convention, it would be difficult to tell the difference between a type variable and an ordinary class or interface name.

Dieses Argument ist bei mehrfach verschachtelten Typen nicht ganz von der Hand zu weisen. Aber gerade dann sind sprechende Typparameternamen hilfreich! Eine einfache Lösung wäre, Typparameter komplett in Großbuchstaben zu schreiben:

interface Matrix<ELEMENT> extends List<List<ELEMENT>>

Hier ist ziemlich einfach erkennbar, dass Matrix und List die Namen von Schnittstellen sind, während ELEMENT ebenso gut erkennbar der Name des Typparameters ist. Allerdings wird diese Konvention in keiner der hier erwähnten Sprachen verfolgt.

In einem zeitgemäßen Editor ist die Unterscheidbarkeit auch bei Verwendung des Namensschemas von Klassen und Schnittstellen dank Syntaxhervorhebung kein großes Problem:

Typparameter werden in IDEs farblich hervorgehoben

Allerdings ist farbige Syntaxhervorhebung zum Beispiel in Büchern in der Regel nicht vorhanden. Wer auf Nummer sich gehen will, kann deshalb Großbuchstaben verwenden oder Microsofts Weg folgen und dem Namen ein T voranstellen.

Zusammenfassung

Typparameter sollten genau wie Klassen, Variablen oder Methodenparameter selbsterklärende Namen haben, um das Verständnis des Quelltextes zu erleichtern. Wenn es nur einen einzigen Parameter mit einem völlig beliebigen Typ gibt, reicht T aus.

In allen anderen Fällen schlage ich eine der folgenden Konventionen vor: