Ausgetrickst

Typ-Inferenz ist eine feine Sache. Macht sich doch der Compiler Gedanken darüber, welchen Typ der Programmierer gemeint haben mag. Damit reduziert sich der Schreibaufwand enorm und der Code wird verständlicher – so die Hoffnung. Aber ist es wirklich eine gute Idee, dass der Compiler mehr weiß als der Programmierer?

vorlesen Druckansicht 8 Kommentare lesen
Lesezeit: 5 Min.
Von
  • Michael Wiedeking

Was wäre ich wohl ohne meine Entwicklungsumgebung? Ich glaube, diese eher rhetorische Frage lasse ich besser unbeantwortet. Auf jeden Fall weiß meine IDE deutlich mehr über alles Bescheid als ich. Sie kennt alle Pakete, darin alle Klassen und von deren Objekten auch noch sämtliche Methoden, Variablen und Konstanten.

Ich kann mir gar nicht mehr richtig vorstellen, wie es damals ohne sie war. Ich musste entweder alles im Kopf haben, musste Bücher wälzen oder zumindest meinen Editor verlassen, um im Browser die Dokumentation zu konsultieren. Das ist aber bei der heutigen Menge an Bibliotheken und Frameworks praktisch unmöglich geworden.

So bin ich mehr als dankbar, dass es die IDE möglich macht, die für einen bestimmten Kontext nötige Information punktgenau zu liefern. Die IDE kann also noch viel mehr. Wegen ihrer Allwissenheit kann sie mir Vorschläge machen. Dazu gehört genauso das Anbieten von möglichen Methoden wie das Erkennen und Korrigieren von Fehlern.

Neuerdings machen auch die Compiler Anstalten, einem die Arbeit zu erleichtern. Was die funktionalen Sprachen schon von jeher bieten, hält nun auch Einzug in die "halbwüchsigen" Sprachen. So bietet beispielsweise C# das Schlüsselwort var, mit dessen Hilfe eine Variable ohne weiteres Zutun den Typ zugeordnet bekommt, den der dazugehörige Initialisierungsausdruck hat.

var i = 0;

Bei solch einfachen AusdrĂĽcken ist das sehr intuitiv. Es gestaltet sich aber umso schwieriger, je spezieller die rechte Seite ist.

var names = p.getNames();

Hier tut sich nun aber ein ganz neues Problem auf. Ich kenne den Typen von names nicht mehr. NatĂĽrlich kann man sich auf den Standpunkt stellen, dass dies doch aus dem Methodenaufruf ableitbar ist. Offensichtlich handelt es sich doch um mehrere Namen, spiegelt sich das doch durch die Mehrzahl sowohl in dem Methoden- als auch im Variablennamen wider.

Anfangs fand ich diese implizite Typisierung auch nicht schlecht – muss man sich doch deutlich weniger mit lästigen Typen rumschlagen. Speziell bei komplizierten Ausdrücken wie

var names = new List<Set<Name>>();

erspart man sich die komplette Wiederholung der redundanten Information auf der linken Seite.

Inzwischen bin ich allerdings eines Besseren belehrt worden. Ich habe ja neulich schon von meinem Abenteuer mit Scala berichtet. Nach der Entscheidung gegen Scala – wobei ich Scala wirklich nachtrauere – habe ich meine mehr als hundert Klassen nach Java konvertiert. Bei dieser Umstellung war ich nun gezwungen, sämtliche jener "Abkürzungen" explizit zu typisieren. Und dabei hatte ich dann deutlich mehr Probleme, als ich für möglich gehalten hätte.

Was nämlich dem Compiler ohne Schwierigkeiten möglich ist, kostete mich dann doch einiges an Nerven. Sicher, die IDE konnte Abhilfe schaffen, da sie mir die Signatur der jeweiligen Methode und damit den gesuchten Typ verraten konnte. Bei der Gelegenheit fiel mir dann auch erst auf, dass – bedingt durch diese implizite Typisierung – die Imports fehlen. Mit Hilfe der Imports wird ja schließlich nicht nur dem Compiler mitgeteilt, welche Pakete, Namensräume und Klassen Verwendung finden. Damit fehlt der grobe Überblick, dass die aktuelle Klasse beispielsweise die Pakete X und Y verwendet.

FĂĽr mich und meine Zukunft hat diese Erfahrung die folgenden Konsequenzen: Mit Ausnahmen von Literalen und expliziten Konstruktor-Aufrufen werde ich die implizite Typisierung nicht verwenden.

var names = new List<Name>(); // OK

Damit erliege ich insbesondere bei Ausdrücken, denen der Typ nicht unmittelbar anzusehen ist, nicht mehr der Versuchung mir Schreibarbeit zu sparen, was ich später bereuen könnte.

var anything = thing.transmogrify(); // Höchst bedenklich

Und mein Gedächtnis ist lange nicht mehr so gut wie früher, sodass ich oft schon nach wenigen Wochen vergesse, was ich denn da schon wieder fabriziert habe.

Typ-Inferenz gibt es ja noch in anderen Zusammenhängen, beispielsweise bei Lambda-Ausdrücken in C#. So darf man anstatt

(int x, int y) => (2 * x + 3 * y)

zu schreiben, wenn es der Kontext hergibt und der Compiler das eindeutig ableiten kann, auch gerne nur

(x, y) => (2 * x + 3 * y)

schreiben. Auch hier werde ich meiner Bequemlichkeit nur dann freien Lauf lassen, wenn der Ausdruck hinreichend einfach ist.

Möglicherweise ist die Vorgehensweise nicht gerechtfertigt, aber sie ist durch meine Arbeitsweise bedingt: Anscheinend helfen mir die Imports und die lästige Typ-bezogene Schreibarbeit dabei, den Sinn eines Programms zu verstehen. Vielleicht ist diese Arbeitsweise nicht mehr zeitgemäß, und ich darf mich immer mehr auf IDE und Compiler verlassen.

Aber sei's drum, in Java gibt es diesen "Luxus" weitgehend nicht. Und so sehe ich mich – zumindest in nächster Zeit – nicht wirklich gefährdet. ()