Advanced Scala – Varianz

Kontravarianz

Wenn Kovarianz durch ein Plus-Zeichen deklariert wird, dann liegt auf der Hand, wodurch Kontravarianz deklariert wird: durch ein Minus-Zeichen. Ebenso liegt auf der Hand, dass der Compiler wohl kaum obige für Kovarianz funktionierende Kiste als kovariant durchgehen lässt:

scala> class Box[-A <: fruit="" fruit:="" a="">:6: error: contravariant type A occurs in covariant position in type => A of value fruit
...

Die Fehlermeldung ist quasi spiegelverkehrt zur vorherigen und wie schon gesagt eigentlich völlig logisch. Aber wie bekommen wir nun eine kontravariante Kiste, die auch dem Compiler zusagt? Ganz einfach: Es muss eine Kiste sein, aus der wir nichts mehr heraus bekommen. Aber etwas hinein geben, das dürfen wir sehr wohl:

class Box[-A <: fruit="" def="" add="" a="" println="" to="" box:="">

Eine solche Kiste können wir also entsprechend der umgekehrten Vererbungsbeziehung verwenden:

scala> val appleBox: Box[Apple] = new Box[Fruit]
appleBox: Box[Apple] = Box@72213339

Da der Typparameter nur in kontravarianten Positionen auftaucht, nicht jedoch als Rückgabetyp einer Methode oder als lesbares Feld, spielt der Compiler mit.

Fazit

Scala ermöglicht uns, das Thema der Varianz in den Griff zu bekommen: Wir können generische Typen ko- oder kontravariant machen, wobei uns der Compiler hilft, dass wir die Einschränkungen des jeweiligen Varianz-Typs beachten, d.h. keine Fehler machen.

Wem das kompliziert erscheint, der hat vollkommen recht! Aber das liegt nicht an Scala, sondern am Thema selbst. Das sieht man zum Beispiel an Java, wo Varianz bei Arrays völlig falsch gemacht wurde. Und außerdem ist es nur für diejenigen von uns kompliziert, die generische Typen mit Varianz programmieren dürfen. Wer solche Typen nicht nutzt, kommt hingegen in den Genuss, ein mächtiges und komplexes Feature ganz einfach verwenden zu können. Ein gutes Beispiel hierfür sind die Collections, die sehr angenehm zu verwenden sind und automatisch „das Richtige“ tun. Wer aber einen Blick auf die Typ- und Methoden-Signaturen wirft, der kann erahnen, was sich dahinter verbirgt.

Heiko Seeberger ist geschäftsführender Gesellschafter der Weigle Wilczek GmbH und verantwortlich für die technologische Strategie des Unternehmens mit den Schwerpunkten Java, Scala, OSGi, Eclipse RCP, Lift und Akka. Zudem ist er aktiver Open Source Committer, Autor zahlreicher Fachartikel und Redner auf einschlägigen Konferenzen.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.