Larry Wall gibt den Rakudo-Perl-6-Compiler auf MoarVM für den produktiven Einsatz frei

Seite 3: Typen

Inhaltsverzeichnis

Von der angedeutete Typklassenhierarchie haben sogar diejenigen etwas, die sie nicht kennen, da Perl ganze Zahlen als Int-Objekte speichert und entsprechend optimieren kann. Die reine Integer-Schleife ist einer der wenigen Fälle, in denen Rakudo um mehr als den Faktor zehn schneller ist als Perl 5. Bei gebrochen-rationalen Zahlen rechnet Perl mit Zähler und Nenner, um Rundungsfehler zu vermeiden. (0.1 + 0.2 - 0.3 ergibt tatsächlich 0, was in den meisten Sprachen einschließlich Perl 5 leider nicht der Fall ist. Ändert ein Container seinen Inhalt, legt das System ein neues Wertobjekt an und verwirft das alte, sofern keine andere Variable auf es verweist. Damit können Int und Str (String) bis zur Auslastung des Hauptspeichers wachsen. Bei Typen mit begrenzter Kapazität erfolgt automatisch der Wechsel zu einer passenden Alternative, sofern der Container nicht auf einen Datentyp festgelegt ist:

  my Rat $breite = ....     # Typ für "kleine", rationale Zahlen

Unbemerkte Typkonvertierungen geschehen auch bei 3 + "", das weiterhin 3 ergibt. Anstatt das + wie in Java zu überladen, vollführt es in Perl immer die numerische Addition. + konvertiert seine Operanden zu Zahlen eines passenden Typs, signalisiert damit den numerischen Kontext, so wie ~ den String-Kontext und ? den boolschen. Gleiches gilt für < (numerisch) und lt (String), die wie gewohnt funktionieren, aber auch beliebige Objekte vergleichen, wenn ihre Klassen Methoden für die Typkonvertierung mitliefern. Ansonsten können Entwickler auf das generische before beziehungsweise after oder cmp zurückgreifen, das Objekte gleichen Typs vergleicht, wenn sie der Rolle einer geordneten Menge entsprechen. Ist die Voraussetzung erfüllt, gibt ++ den Nachfolger und -- den Vorgänger zurück. Für die Menge der ganzen Zahlen ist das Resultat vertraut, bei einem Date-Objekt könnte sie der nächste oder vorige Tag sein.

Auch wenn Gewohnheit und die Perl-Tugend der Faulheit es nahelegen Typen zu ignorieren, so ist es dennoch bequemer, einen Typennamen in die Signatur einzutragen als sich eine Zeile Parametervalidierung nebst Fehlermeldung auszudenken. Ein passender Subtyp ist zudem schnell erzeugt:

    # Untertyp gerade Zahlen sind Int, die teilbar(%%) durch 2 sind
subset Even of Int where * %% 2;
sub f (Even:D $g){ ...
    # anonymer Untertyp vor Ort erzeugt (ohne Wiederverwendbarkeit)
sub f (Int:D $g where * %% 2){ ...

:D ist ein Type-Constraint, der nur D wie definierte Werte zulässt. Ohne ihn würde die erste Signatur bei folgendem keinen Fehler geben:

    my Even $bin_undefiniert;
f($bin_undefiniert);
say $bin_undefiniert.WHAT; # "(Even)"

Ohne :D prüft die erste Signatur auf Typengleichheit, ohne den Variableninhalt zu beachten. Die zweite Signatur muss den Inhalt auf Einhaltung der der Subtypdefinition prüfen.

Sämtliche Daten, Datentypen und sonstige Konstrukte sind intern als Objekte organisiert. Dazu gehören auch die Metaobjekte, die alle Informationen zu einem Objekt verfügbar machen und das Objektverhalten ändern können. Das ist ein weiterer Grund, warum die Perl-Anpassung geringe Kenntnisse erfordert. Neben den Grundlagen der OOP genügt ein Verständnis der autogenerierten Getter/Setter, von Multimethoden und der Rollen um einen Überblick zu gewinnen.

Der . ist die sekundäre Sigil der öffentlichen Attribute mit gleichnamigen Accessoren, das ! kennzeichnet private Attribute:

    has Str @.radio is rw = 'Start';
has $!notruf;

Da @.radio rw (read/write) ist (der Standard ohne Deklaration wäre ro, also readonly), ist das Setzen des Wertes außehalb der Klasse möglich: $objekt.radio = .... Multimethoden unterscheiden sich in Signatur, aber nicht dem Namen nach, sodass Perl beim Aufruf $obj.nachricht(3); (so spät wie möglich) das Passende aus folgenden Methoden findet oder mit einem Fehler abbricht:

    multi method nachricht(Int $msg) {...}
multi method nachricht(Str $msg) {...}

Entwickler können jede als muli definierte Routine Operator mit eigenen Multimethoden erweitern, was auch Operatoren einschließt.

Rollen fangen mit role an und besitzen ansonsten nahezu dieselbe Deklaration wie Klassen. Von ihnen wird keine Instanz abgeleitet, sondern der Befehl does mischt sie Klassen und Objekten zur Kompilierungs- und Laufzeit bei. Wegen ihrer Flexibilität vergleicht Larry Wall diese Art der Vererbung mit einem Verhalten, das man anlegen kann – im Gegensatz zum weniger veränderlichen Sein. Passend zu der Analogie deklarieren Entwickler die Klassenvererbung mit is. Beim Anbringen einer Rolle erfolgt eine Kollisionsüberprüfung der Methoden, was ein Vorteil gegenüber Mixins ist. Methoden mit leerem Rumpf fordert die Rolle von der einzubindenden Klasse, was das Schreiben reiner Interfaces ermöglicht. Der wichtigste Grund für Rollen ist jedoch der Aufbau flacher und handhabbarer Klassenhierarchien. Perl 6 kennt auch parametrisierte Rollen für eigene abstrakte Datentypen.