Wikipedia · einfach zusammengefasst · Stand
Typisierung (Informatik)
B. Variablen, Funktionen oder Objekte (im Sinne der objektorientierten Programmierung) korrekt verwendet werden. Ein Ziel der Typisierung ist die Vermeidung von …
Inhalt4 Abschnitte
Grundidee und Zweck
Typisierung sorgt in Programmiersprachen dafür, dass Programmelemente wie Variablen, Funktionen und objektorientierte Objekte korrekt verwendet werden. Ein wichtiges Ziel ist, Laufzeitfehler zu vermeiden.
Ein Typsystem ist eine Komponente einer Programmiersprache, die den Wertebereich von Variablen einschränken kann. Eine Sprache mit einem Typsystem heißt typisiert. Abhängig von dessen Ausprägung wird gelegentlich zwischen stark und schwach typisierten Sprachen unterschieden.
Das Typsystem erkennt Typverletzungen während der Übersetzung oder Ausführung. Dadurch soll verhindert werden, dass auf Variableninhalte syntaktisch oder semantisch fehlerhafte Operationen angewendet werden. Typinformationen bilden dabei eine zusätzliche Absicherung: Sogenannte Typinvarianten verhindern, dass eine Variable Werte erhält, die sie nicht annehmen sollte. Damit werden unmögliche oder aus Sicht der Programmlogik nicht sinnvolle Operationen vermieden.
Typumwandlungen und Bestandteile
Zu den Aufgaben der Typisierung gehört die Typumwandlung (type conversion). Unterschieden werden:
- Typumwandlung im engeren Sinne; in vielen objektorientierten Sprachen steht dafür der cross cast zur Verfügung.
- Beförderung eines Typs (type promotion) durch einen up cast.
- Degradierung eines Typs (type demotion) durch einen down cast.
Ein Typsystem umfasst zunächst die Typen selbst. Sie werden entweder durch Typdefinitionen erzeugt oder sind als primitive Datentypen fest in die Sprache eingebaut. Hinzu kommt die Möglichkeit, Programmelemente wie Variablen oder Methodenparameter durch eine Typannotation mit einem bestimmten Typ zu deklarieren.
Weitere Bestandteile sind Regeln, die den Wert eines Ausdrucks einem Typ zuordnen, sowie Regeln zur Prüfung der Zuweisungskompatibilität: Sie bestimmen, ob ein Wert eines Typs einer bestimmten Variable zugewiesen werden darf. Optional gibt es typbezogene Operatoren wie „instanceof“ oder eine Reflection API, mit der ein Programm Typinformationen zur Laufzeit ermitteln und prüfen kann.
Arten von Typsystemen
Typsysteme lassen sich entlang vier Dimensionen einordnen:
- Statische und dynamische Typisierung: Bei statischer Typprüfung werden Typen zur Übersetzungszeit geprüft. Zuweisungsfehler können dadurch bereits vor der Laufzeit gefunden werden. Bei dynamischer Typprüfung fallen solche Fehler erst zur Laufzeit auf. Dafür ermöglicht sie mächtigeres Verhalten, etwa die korrekte Verarbeitung eigentlich inkompatibler Typen und Erweiterungen zur Laufzeit.
- Explizite und implizite Typisierung: Bei expliziter Typisierung nennt der Programmierer die Datentypen. Bei impliziter Typisierung werden sie durch Typableitung (type inference) ermittelt.
- Starke und schwache Typisierung: Entscheidend ist, wie streng eine Sprache Typen voneinander unterscheidet, welche Typen ineinander umgewandelt werden können und ob implizite oder unsichere Umwandlungen erlaubt sind. Unsichere Typumwandlungen können beispielsweise Werte verlieren.
- Optionale Typisierung: Typannotationen unterstützen die Programmierer, haben aber keine Auswirkungen auf die tatsächliche Umsetzung durch den Compiler zur Laufzeit.
Die Einordnung einer Sprache ist teilweise subjektiv. C++ gilt beispielsweise als stärker typisiert als C, aber als schwächer typisiert als OCAML. Außerdem kann ein Typsystem abhängig von der Verwendung mehrere Aspekte besitzen, etwa bei polymorphen Werten oder Typumwandlungen.
Typische Sprachbeispiele
x86-Assembler wird im Artikel als Beispiel ohne Typisierung genannt: Einzelne Bytes eines Registers können unmittelbar mit Zahlen- oder Zeichenwerten belegt werden.
C gilt als statisch, explizit und schwach typisiert. Eine Variable kann ausdrücklich als int deklariert werden; zugleich zeigt das Beispiel Zuweisungen zwischen Ganzzahlen und Speicheradressen, die wegen eines undefinierten Wertes sogar zu einem Programmabsturz führen können.
C# wird als statisch und dynamisch, explizit und implizit sowie stark typisiert eingeordnet. Im Beispiel werden int und short von Math.Max verarbeitet. Die ausdrückliche Umwandlung eines object in int kann eine InvalidCastException auslösen; ein undefinierter Wert kann eine NullReferenceException verursachen. Bei der Rückgabe wird int durch Boxing implizit in object umgewandelt.
Java ist im Beispiel statisch, explizit und implizit sowie stark typisiert. Die Umwandlung von Object in int kann eine ClassCastException verursachen, ein undefinierter Wert eine NullPointerException. Der Rückgabewert wird durch Boxing implizit zu Integer.
OCAML gilt als statisch, implizit und stark typisiert. Bei einer Additionsfunktion erkennt die Sprache selbst den Typ float -> float -> float. Der Aufruf mit int und float führt zu einem Compilerfehler; nach der ausdrücklichen Umwandlung mit float_of_int ergibt die Addition von 1 und 2.5 den Wert 3.5. Ein weiteres Beispiel wandelt ein Objekt mit den Methoden a und b in einen Typ um, der nur die Methode a verlangt, damit es gemeinsam mit einem entsprechenden Objekt in einer Liste gespeichert werden kann.
Pascal wird als statisch und dynamisch, explizit und stark typisiert dargestellt. Mit chr wird die Ganzzahl 33 in das entsprechende ASCII-Zeichen umgewandelt, mit ord wieder zurück; die Ausgabe lautet „33 !“. Eine Division, deren Ergebnis nicht ganzzahlig ist, verursacht bei der Zuweisung an eine integer-Variable einen Laufzeitfehler.
Perl und PHP gelten als dynamisch, implizit und schwach typisiert. Perl verwendet bei „4-2“ nur den am Anfang stehenden Zahlenteil 4 und erhält bei 1.5 + „4-2“ den Wert 5.5; „text“ trägt keinen Zahlenwert bei. PHP wandelt „42“ bei 2 + „42“ in eine Zahl um und erhält 44. Im gezeigten Beispiel wird eine ungültige Zeichenkette zu 0, sodass das Ergebnis 2 ist.
Python ist dynamisch, implizit und stark typisiert. 2 + „42“ löst einen TypeError aus. Erst int(„42“) erzeugt die Zahl, sodass das Ergebnis 44 lautet. int(„Ich bin keine Zahl“) führt zu einem ValueError.
Pike wird als statisch und dynamisch, explizit und stark typisiert eingeordnet. Die direkte Verknüpfung einer Zahl mit einer Zeichenkette kann einen Kompilier- oder Laufzeitfehler verursachen; die Zuweisung von „42“ an eine int-Variable führt zu einem Kompilierfehler. Eine ausdrückliche Umwandlung von „42“ in int ermöglicht das Ergebnis 44. Im Beispiel wird eine ungültige Zeichenkette bei der Umwandlung zu 0, sodass das Ergebnis 2 ist.