Flexibles Typsystem in C (Teil 2)
Kommentare

Covariance
Einfach ausgedrückt ermöglicht Covariance die implizite Typkonvertierung eines Typen auf einen kompatiblen Typen. Dabei stellt die Eigenschaft Covariance die Zuweisungskompatibilität (assignment

Covariance

Einfach ausgedrückt ermöglicht Covariance die implizite Typkonvertierung eines Typen auf einen kompatiblen Typen. Dabei stellt die Eigenschaft Covariance die Zuweisungskompatibilität (assignment compatibility) sicher. Wie im Beispiel aus Listing 1 erkennbar wurde, kann ein kleinerer Typ immer durch einen mehr generischen Typen ausgetauscht bzw. substituiert werden. Listing 2 zeigt dazu ein weiteres Beispiel. Die instanziierte Liste vom Typ List wird einer Variablen zugewiesen, die von einem allgemeineren Typ ist. Danach wird diese Variable einem generischen IEnumerable mit dem Typ object zugewiesen. Dies ist durch die garantierte Zuweisungskompatibilität (assignment compatibility) möglich.

Listing 2

public static void Covariance() {
  IEnumerable liste = new List();
  IEnumerable objList = liste;
}  

Covariance und Arrays

Arrays, die als Elementtyp einen Referenztyp halten, sind schon seit der ersten .NET-Version covariant. Dieses Verhalten kann allerdings in manchen Situationen zu Problemen führen, da die Typsicherheit hierbei nicht durchgängig zur Übersetzungszeit überprüft werden kann. In der ersten Methode in Listing 3 wird ein Array mit Elementen vom Typ Procedural angelegt und einer zweiten Methode übergeben. Die zweite Methode erwartet als Parameter ein Array vom Typ Binary. Die Übergabe des Procedural Array ist gültig, da der Typ Binary die Basisklasse von Procedural ist und somit die beiden Typen kompatibel sind. In der zweiten Methode wird allerdings versucht, eine Instanz vom Typ Haskell dem eigentlichen Procedural Array hinzuzufügen. Diese fehlerhafte Zuweisung wird leider erst zur Laufzeit erkannt und führt zu einer ArrayTypeMismatch-Ausnahme.

Listing 3

public static void ArrayCovariance()
{
  Procedural[] proc = new Pascal[20];
  typeMismatch(proc);
}
public static void typeMismatch(Binary[] arr)
{
  arr[0] = new Haskell();
}  

Contravariance

Contravariance verhält sich umgekehrt zu Covariance und ist vor allem interessant bei der Definition von Funktionen. Im oberen Bereich von Listing 4 wurden drei Methoden ohne Rückgabewert aber mit einem Parameter definiert. Als Parameter wird bei den ersten beiden Methoden eine kompatible Instanz vom Typ Binary erwartet. Die definierte dritte Methode erwartet einen Parameter vom Typ Assembler. In der vierten Methode werden die zuvor angelegten Methoden jeweils Funktionsdelegaten (Delegates) zugewiesen. Die ersten beiden Delegates legen als Parametertyp jedoch einen spezielleren (größeren) Typen fest als die ersten beiden Methoden. Durch die gegebene Contravariance ist die Zuweisung aber gültig und wird kompiliert und ausgeführt. Die Zuweisung der dritten Methode zu dem Delegate ist jedoch ungültig, da dieser den übergeordneten Typen Binary definiert. Das heißt, schon während der Übersetzungszeit ist der Compiler nicht in der Lage, die beiden Typen zusammenzubringen.

Listing 4

public static void CompileSource(Binary bin) {}
public static void Print(Binary bin) {}
public static void Save(Assembler assembler)
public static void DelTest()
{
  Action handle1 = CompileSource;
  Action handle2 = Print;
  Action handle3 = Save; // NICHT MÖGLICH
}  
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -