Perl 6
Perl 6 Tutorial Part 2: Revision 1


Fast keine Einleitung

Herzlich willkommen zur zweiten Folge dieses umfassenden Perl 6-Tutorials. Rakudo und ein Editor der Wahl sind hoffentlich griffbereit und wir beginnen sofort. Wer noch weitere einleitenden Worte möchte, findet diese im ersten Teil, in der vorigen Ausgabe.

Perl ist eine operatorbasierende Programmiersprache

Unlängst konnte ich herzlich lachen, als ich diesen Satz in der p6l-Mailingliste sah. Der wahre Kern dieser Pointe besteht darin, daß Perl 6 tatsächlich auffallend viele Operatoren besitzt und das Operatoren einen bedeutenden Anteil an Perl's Ausdrucksstärke haben. Und weil Operatoren bereits mit wenig Quellcode angewendet werden können, eignen sie sich vortrefflich als Einstieg in die Tiefen der Sprache. Letztlich ist ihre Kenntnis auch eine wichtige Vorraussetzung für spätere, umfangreichere Beispiele.

Ein wenig Numerik zum aufwärmen

Beginnen wir ganz einfach mit den geläufigsten Operatoren, den Grundrechenarten ('+', '-', '*'), die jeder Insasse dieser Zivilisation vom Grundschullehrer nahe gebracht bekommt.

<verbatim>
say 3 + 4; # 7
say 3 - 4; # -1
say 3 * 4; # 12
</verbatim>

Ebenso zeigte euch der freundliche Mathelehrer auch die Division, Modulo (Rest einer ganzzahligen Division) und Potenzierung, nur werden die in Computersprachen etwas anders geschrieben als im Unterricht, da man hier in den alten Tagen auf den ASCII-Zeichensatz beschränkt war.

<verbatim>
say 3 / 4; # 0.75
say 3 % 4; # 3 ( 3 div 4 = 0 Rest 3 )
say 3 ** 4; # 81 ( = 3 * 3 * 3 * 3 )
</verbatim>

Algebra unter erschwerten Bedingungen

So weit erfüllen die Ergebnisse die Erwartungen eines Mathematikers und zeigen, daß @larry noch wissen, welche Dinge sie besser nicht ändern. Was Mathematiker jedoch nicht erwarten, aber sehr wohl Perl-Programmierer kennen, die mit Daten zweifelhafter Herkunft hantieren, sind Zahlenwerte, die Buchstaben enthalten können. Diese übergeht Perl großzügig, in dem es alles ab dem ersten Zeichen ignoriert, das nicht als Zahl interpretiert werden kann. Das wird Überführung eines Wertes in den numerischen Kontext genannt und geschieht immer dann, wenn Perl anhand der verwendeten Operatoren erkennt, daß hier mit Zahlen gerechnet wird. Folgende Beispiele geben gleiche Ergebnisse unter Perl 5 und 6 aus. Die Kommanotation von 'print' hab ich deswegen gewählt, damit die Beispiele wirklich unter Perl 5 und 6 laufen, da Strings in beiden Sprachen unterschiedlich zusammengefügt werden.

Perl 5 & 6:
<verbatim>
print 3 * '2.2j4',"\n"; # 6.6, da 3 * 2.2
print 3 * 'b2.2j4',"\n"; # 0, da 3 * 0
print - '2.2ah',"\n"; # -2.2, einfache Negierung
</verbatim>

Die Unterschiede beginnen, wenn man das '+' als Präfixoperator benutzt.

Perl 5 & 6:
<verbatim>
print + '2.3ah',"\n";
print int '2.3ah'; # 2
print abs '-2.4ah'; # 2.4
</verbatim>

Während Perl 5 dieses '+' ignoriert, überführt es in Perl 6 den folgenden String in den numerischen Kontext, wie das '-' in Perl 5 und 6, nur ohne zu negieren. Zwar gab es bereits in Perl 5 'int', welches ganze Zahlen zurückgibt und 'abs' das positive Zahlenwerte liefert, aber eine einfache und direkte Umwandlung in den numerischen Kontext gab es erstaunlicherweise bisher nicht.

Noch mehr Numerik zum vertiefen

<verbatim>
say + '2.3ah'; # 2.3
say - '2.0ah'; # - 2
</verbatim>

Diese Beispiele sind es wert, längere Zeit meditativ betrachtet zu werden. Denn sie beschreiben eine grundlegende Arbeitsweise vieler Operatoren. Perl 6 kennt nämlich nicht nur Skalar, Array und Hashkontext, sondern noch viele mehr, wie zum Beispiel den numerischen Kontext. Dessen Symbol ist quasi das '+', welches diesen nicht nur erzwingt sondern auch Sigil für eine Reihe von Operatoren ist, die ebenfalls diesen Kontext forcieren. Sie sind bereits als bitverändernde Ops bekannt, aber äusserlich kaum wiederzuerkennen. Die guten, alten Shiftoperatoren werden jetzt z.B.'+&lt;' und '+&gt;' geschrieben, wie das nächste Beispiel zeigt. Das sieht zuerst ungewohnt aus, ist aber logisch, weil meist nur der numerische Wert, den eine Zeichenkette ausdrückt, für Bitoperationen gebraucht wird. Ausserdem sind '&lt;&lt;' und '&gt;&gt;' jetzt interpolierende Schwestern der '&lt;' und '&gt;'-Klammern geworden. So wie "" interpolierende Schwestern von '' sind. Analog zum Erklärten sind die bitweisen 'und'(and), 'oder'(or) und 'entweder-oder'(xor) nun '+&', '+|' und '+^'. Die einfachen logischen Operatoren '&', '|' und '^' sind jetzt junktiv. Das werde ich genauer im Teil 3 erklären, weil es auch den Umgang mit Arrays berührt.

<verbatim>
say 5 +< 2; # 20; 10100 = 101 << 2
say 5 +> 2; # 1; 001 = 101 >> 2
say 5 +& 3; # 1; 001 = 101 & 011
say 5 +| 3; # 7; 111 = 101 | 011
say 5 +^ 3; # 6; 110 = 101 ^ 011
</verbatim>

Die meisten sonstigen numerischen Operatoren bleiben wie bekannt, lediglich das Autoincrement (++) und Autodecrement (--) sind nun keine reinen numerischen Op's mehr. Bevor ihr einen Herzschlag bekommt: klar verändern sie Zahlenwerte um 1. Aber sie erzwingen keinen Kontext, sondern passen sich ihm an. Denn sie sind allgemeine Operatoren geworden, die den Vorgänger oder Nachfolger eines Wertes rufen und bedienen sich daher des gleichen Mechanismus wie einige Vergleichsops. Ähnlich brechnen auch 'div' und 'mod' (auf Zahlen angewendet) Division und Modulo, können sich aber einem anderen Kontext auch anpassen.

<verbatim>
my $a = 5;
say ++$a; # 6 (5 + 1)
say $a++; # 6 (erhöht wird danach)
say --$a; # 6 (6 + 1 - 1)
say $a--; # 6 (verringert wird danach)
say $a --; # Error
</verbatim>

Routinierte Perlprogrammierer sollten nicht vergessen, daß jetzt zwischen Variable und ihrem Präfix- oder Suffixoperator kein Leerzeichen stehen darf. Die Gründe hab ich im vorigen Teil des Tutorials dargelegt.

Operatoren des Stringkontext

Analog zum numerischen gibt es, wie erwarted, auch einen Stringkontext, dessen Symbol '~' ist. Warum die Tilde? Nun, weil der ultimative Textoperator '=~' hieß, also Tilde schon immer etwas mit Strings zu tun hatte und der Punkt, wie letzes mal schon gezeigt, nun die Objektorientierung ausdrückt. Die Tilde wandelt also in den Stringkontext um und kann auch Strings verknüpfen, wie der Unixbefehl 'cat', den es jetzt auch innerhalb von Perl gibt.

<verbatim>
say ~ '2.3ah'; # '2.3ah'
say ~ '2.0'; # '2.0'
say ~ 0xff; # 255
say 'rot ' ~ 'blau' # 'rot blau'
say cat('rot ', 'blau'); # dito
say 'Farbe:' ~ color(); # eine Testausgabe
</verbatim>

Die Tilde kann aber auch genauso mit den bitveränderndem Operatoren kombiniert werden, wie im numerischen Paralleluniversum das Plus. Auch wenn ich bis heute keinen praktischen Nutzen, für die daraus entstehenden Operatoren gefunden habe, will ich nicht ausschließen das es einen gibt. Die Tilde signalisiert, daß die Werte zeichenweise in Ordinalzahlen umgewandelt werden (mit 'ord'). Auf die so entstandenen Reihen numerischer Werten, können nun die bitweisen Rechenarten problemlos angewendet werden. Lediglich beim shiften muß der rechte Operand eine Zahl sein. Die Ergebnisse werden dann selbstverständlich vor der Ausgabe wieder mit 'chr' in Textzeichen umgewandelt.

<verbatim>
'-' ~< 1 ; #'Z'= chr 90 ( 45 << 1 )
'z' ~> 1 ; #'='= chr 61 ( 122 >> 1 )
'a' ~& 'D'; #'@'= chr 64 (1100001 & 1000100)
'a' ~| 'D'; #'e'= chr 101 (1100001 | 1000100)
'a' ~^ 'D'; #'%'= chr 37 (1100001 ^ 1000100)
</verbatim>

Perl 6 kennt aber erfreulicherweise auch die bekannten Befehle zur Bearbeitung von Zeichenketten wie 'index', 'substr', 'uc', 'lc' und so fort und sogar rubysche Spielereien wie reverse, welches die Reihenfolge der Zeichenkette umkehrt. Genau genommen sind das aber eingebaute Funktionen und keine Operatoren, um die es hier geht. Die bestehen aus wenigen, nicht alphanumerischen Zeichen. Obwohl, das stimmt eigentlich auch nicht, denn Perl 6 kennt ebenfalls noch das kleine 'x', mit dem Perlschreiber schon früher Strings vervielfältigten.

<verbatim>
'a' x 5; # 'aaaaa'
'so' x 3; # 'sososo'
</verbatim>

Bei wirklich komplexen Fällen, führt jedoch kein Weg an den regulären Ausdrücken vorbei! Die nennen sich jetzt rules und bieten derart viele Möglichkeiten, daß sie hier mindestens einen eigenen Teil benötigen. Deswegen folgen jetzt nur wenige Beispiele um den in Perl 5.10 eingeführten Smartmatchoperator zu demonstrieren. Dieser ersetzt in Perl 6 das '=~' vollständig.

<verbatim>
"Ich hab getanzt ..." ~~ m/tanz/; # 1
"Ich hab getanzt ..." !~~ m/wanze/; # 1
"Ich hab getanzt ..." ~~ s/tan/schwit/; # Error
</verbatim>

Im Gegensatz zu Perl 5 liefert er aber nur einen boolschen Wert zurück, der den Erfolg der Suche meldet. (Auch beim Ersetzen.) '!~~' negiert am Ende der Suche lediglich diesen Ergebniswert. Jede weitere Information zum Suchvorgang können Programmierer wie gewohnt den Spezialvariablen entehmen, deren Syntax sich auch geändert hat. Die Fehlermeldung im Beispiel ist der Tatsache geschuldet, daß nur in Variablen, aber nicht in konstanten Ausdrücken ersetzt werden kann.

Vergleichsoperatoren

Die neue Arbeitsweise des '~~' erklärt sich einfach mit dem Umstand, daß es ein Vergleichoperator wie '==' ist. Der gibt ja auch nur wahr oder falsch zurück. (im perlschen Sinne) Ohne zu übertreiben kann man sogar sagen, das '~~' der Endgegner unter den Vergleichsoperatoren ist, noch weit mächtiger als bereits in Perl 5.10. Je nach Typ und Inhalt seiner Operanden versucht er in jeder Lage etwas sinnvolles abzuliefern und hat dazu eine große Tabelle, die Vorrang und Kompatibilität aller internen Perlobjekte zueinander angibt. Das hat von Natur aus immer etwas mit Unschärfe zu tun und tatsächlich sieht '~~' ein wenig aus, wie das Symbol für das Wort circacirca.

Das genauer Gegenteil dazu ist der Operator '===', der die Identität, also Inhalt und Typ zweier Werte vergleicht. Wem das immer noch nicht genau genug ist, kann noch auf 'eqv' zurückgreifen, welches zusätzlich Laufzeiteigenschaften beachtet.

<verbatim>
1,2 === 1,2; # 0
'3.0' === 3; # 0
</verbatim>

Das erste Beispiel ergab negativ, weil es Referenzen (heißen jetzt Captures) auf 2 unterschiedliche Arrays sind. Das zweite ist ebenfalls negativ, weil für Perl offensichtlich ist, daß der linke Operand ein String ist und der rechte numerisch.

Gewöhnlich entgehen jedoch Perl-Programmierer solchen Problemen, in dem sie auch beim Vergleich den bevorzugten Kontext erzwingen. Wie in Perl 5 zeigen Ops aus mathematischen Symbolen ('&lt;','&gt;','&lt;=','&gt;=','==') den numerischen Kontext an. Vergleichsops aus Buchstaben ('lt','gt','le','ge','eq') vergleichen zeichenweise.

<verbatim>
1,2 == 1,2; # 1
'3.d' == 3; # 1
1,2 eq 1,2; # 1
3.0 eq 3; # 1
</verbatim>

Mit anderen Worten: '$a eq $b' ist eine Kurzschreibweise für '~$a === ~$b' und '$a <span>= $b' kann auch '+$a ==</span> +$b' formuliert werden. Was aber tun, wenn nicht bekannt ist, ob man Zeichen oder Zahlen vergleichen wird? Dann nimmt man '~~', was aber nur gut gehen kann, wenn beide Vergleichswerte immer noch den gleichen Typ haben.

<verbatim>
'5' ~~ 5.0; # 1
'du' ~~ 'du'; # 1
3.0 ~~ '3f'; # 0
</verbatim>

Die oberhalb aufgezählten Vergleichsops brauchen wohl kaum eine Vorstellung, auch nicht ihre negierte Form (mit einem '!' davor). Selbst die verkürzten Formen der 'ungleich'-Operatoren (numerisch '!=' für '!==') und (im string Kontext 'ne' für =!eq=), haben bereits vor langer Zeit ihren Platz in der Perl-Folklore gefunden (jeweils beide Schreibweisen sind in Perl 6 erlaubt). Und doch steckt auch hier eine neue verallgemeinerte Logik hinter diesen Operatoren, denn es gibt weit mehr sortierbare Dinge als Zahlen und Buchstaben, die man praktischerweise mit einem Operator befragen kann, ob sie sich in der gewünschten Reihenfolge befinden. Die Ops dafür sind 'before' und 'after', die leider derzeit noch nicht von Pugs verstanden werden.

<verbatim>
say 3 before 5; # 1
say 'b' after 'a'; # 1
</verbatim>

Somit ist klar, daß '$a &gt; $b' eine andere Schreibart für '+$a after +$b' ist und '$a lt $b' auch als '~$a before ~$b' ausgedrückt werden kann. All die bisherigen Vergleichsop haben jedoch gemeinsam, daß sie ein wahr oder falsch liefern. Nun, eigentlich ist es ein 'Bool::True' oder 'Bool::False', die im normalen, numerischen Kontext zu 1 oder 0 evaluiert werden, doch heben wir uns diese Spitzfindigkeiten für später auf, wenn das interne Objektsystem ansteht. Selbst wenn ich mehrere Vergleiche kombiniere, wie in:

<verbatim>
say 3 < $b < 7; # wird in 1 Zug ausgewertet
say 3 < $b == $b < 7;# in 2 Zügen ausgewertet
</verbatim>

erhalte ich einen boolschen Wert, da nur 2 verschiedene Ergebnisse möglich sind. Im allgemeinen Vergleich sind es jedoch 3: kleiner als, gleich und größer als. Was sich in den Rückgabewerten, wie in P5, als 1, 0 und 1 ausdrückt. Aber vor der Umwandlung in den Ergebniskontext ist es ein =Order::Increase=, =Order::Same= oder =Order::Decrease=. Diese und weitere internen Methoden sind auch dafür sehr nützlich, daß ein Modul wie DateTime sie mit eigenen Routinen überladen kann. (So etwas wie "Tie" gibt es hier nicht mehr.) Stellt dann der Befehl 'cmp' fest, daß er hier 2 Objekte vom Typ DateTime vergleichen soll und die Parameterlisten der bereitgestellten Methoden auch zu den Operanden passen, werden sie verwendet. Und voila, 'cmp' kann auch Zeitpunkte vergleichen. Ähnlich arbeiten auch =++= und =-=, die ebenfalls dank mitgelieferter Methoden, Vorgänger- und Nachfolger eines Objektinhaltes ermitteln können. Jetzt hat mancher Perlkundiger sicher gerufen: "Aber =cmp= forciert doch den Stringkontext?". Richtig, in Perl 5, aber nicht in Perl 6. Hier steht 'cmp' wirklich für 'compare' (vergleiche). Soll beim Vergleich auf numerischen Kontext geachtet werden, so benutze man das bekannte '&lt;=&gt;', im Strinkontext allerdings =leg=. Das hört sich ausgesprochen 'LowerEqualGreater' an und ist parallel zu &lt;=&gt;, an die Anfangsbuchstaben der Namen der verwandten Ops =lt=, =eq=, =gt= angelehnt.

Der dritte Skalarkontext

In diesem Text wurde es schon einige Male unterschwellig erwähnt, Perl 6 kennt auch einen boolschen Kontext. Und er wird mit dem '?' gefordert, da einfache Fragen auch meist mit ja oder nein beantwortbar sind. Wie der numerische, so kennt der boolsche auch einen verneinenden Operator: das Ausrufungszeichen. Eine Umwandlung in den boolschen Kontext tat man bisher eher implizit, z.B. beim einsetzen einer Variable in eine if-Bedingung oder in Verbindung mit logischen Operatoren. Jetzt geht es überall und explizit, auch mit 'true' oder 'not':

<verbatim>
say ? '2.3ah'; # 1
say true 0 ; # 0
say ! '2.3ah'; # ''
say not ''; # 1
</verbatim>

Und sicher gibt es hier ebenfalls die kontexterzeugenden Bitoperatoren. Hier macht es auch ein wenig mehr Sinn als bei Texten. Nur nicht für die Shiftoperatoren, denn bei einem Bit Registerbreiter, gibt es nichts zu shiften.

<verbatim>
say 0 ?& 'aha'; # 0
say 3 ?| '2.3'; # 1
say '' ?^ 4 ; # 1
</verbatim>

Steht das '?^' vor einem einzelnem Operanden, entspricht es einem '!' oder not.

Schlußendlich .. die Auswahloperatoren

Bei den logischen Operatoren gibt es noch eine wohlbekannte Gattung, die den Kontext der Werte nicht verändert, auch wenn sie intern mit den Umwandlungen der Werte in den boolschen Kontext rechnet. Ich nenne sie Auswahloperatoren, da sie den Wert eines Operanden zurückliefern. Manche nennen sie Kurzschlußoperatoren, da sie vorzeitig abbrechen, wenn das Ergebnis absehbar ist. Das kann man dazu nutzen, Befehle bedingt ausführen zu lassen. Ich halte meine Bezeichnung für treffender, da einer aus dieser Gattung ( =xor=), diese Eigenschaft nicht besitzt. Ihr Syntax wird durch die Wiederholung des logischen Operatorzeichens gebildet.

<verbatim>
say 0 && 'aha'; # 0
say 4 and 0 ; # 0
say 3 || 0 ; # 3
say 0 or 5 ; # 5
say '' ^^ 4 ; # 4
say 7 xor 4 ; # ''
</verbatim>

Der mittlere Op hat eine recht neue Variante, die erst Perl 5.10 kennt. Sie nennt sich defined-or und liefert nur dann den rechten Wert, wenn der linke undefniert ist. Die 3 Operatoren des letzten Listings haben noch eine Schreibweise, in der sie mit niedriger Priorität (in einem Ausdruck als Letzte) ausgeführt werden. ( =and= statt =&&=, or statt =||= und xor statt =^^=). Diese wird gebraucht um Terme logisch zu verknüpfen, ohne allzuviel Klammern benutzen zu müssen, die die Lesbarkeit erschweren würden.

Wirklich neu ist in dem ganzen nur das =orelse=. Es funktioniert exakt wie ein =or=, nur das die Spezialvariable =$!= des linken Blocks, auch im rechten Block weiterbesteht, falls dieser ausgeführt werden sollte. Dadurch wird dieser Befehl nützlich, um in knapper Form einen Aufruf oder kleinen Block mit einem zweiten zu verknüpfen, der im Falle eines Problems, die Fehlermeldung des Ersten auswerten kann.

<verbatim>
do {...} orelse { say $! }
</verbatim>

Der wiederum vertraute, ternäre Operator ist nicht direkt ein Auswahloperator, funktioniert aber ähnlich und wurde auch optisch den Auswahloperatoren angepaßt. Das war anders kaum möglich, da Fragezeichen, wie bekannt, jetzt den boolschen Kontext erzwingen.

<verbatim>
$a = defined $b ?? $b !! $c;
$a = $b // $c; # kürzer
</verbatim>

Die kaum noch bekannten Flipflopops wurden umbenannt, um Verwechslungen mit den gleichnamigen Bereichsoperator zu vermeiden ('..' zu =ff= und '...' zu =fff=). Dateitestoperatoren wurden den Perl 6-Konventionen angepaßt und werden nun mit ':' statt '-' am Anfang geschrieben. Sie haben auch negierte Versionen ( =:!=) und können additiv gestapelt aber auch sonstig explizit als Junctions logisch verknüpft werden.

<verbatim>
if $datei ~~ :e { say 'gibts' }
if $datei.:!e { say 'gabs' }
if $datei :r :w :x { ... }
if $datei :r | :x { ... }
</verbatim>

Ich glaube das waren ausreichende Indizien für mein Argument, daß Perl 6 eine operatorbasierende Sprache ist. Mehr wäre auf einmal auch schwer aufzunehmen. Die bisher nicht Erwähnten Operatoren , die vor allem Arrays betreffen, wir der nächste Teil beschreiben.


Previous Chapter | Overview | Next Chapter


Upload Files

Click "Browse" to find the file you want to upload. When you click "Upload file" your file will be uploaded and added to the list of attachments for this page.

Maximum file size: 50MB

 
 
 
File Name Author Date Uploaded Size

Save Page As

Enter a meaningful and distinctive title for your page.

Page Title:

Tip: You'll be able to find this page later by using the title you choose.

Page Already Exists

There is already a page named XXX. Would you like to:

Save with a different name:

Save the page with the name "XXX"

Append your text to the bottom of the existing page named: "XXX"

Upload Files

Click "Browse" to find the file you want to upload. When you click "Add file" this file will be added to the list of attachments for this page, and uploaded when you save the page.

 
 
 
Add Tags

Enter a tag and click "Add tag". The tag will be saved when you save the page.

Tag: 

Suggestions: