Perl 6 für Perl 5-Programmierer
Trotz vieler Änderungen von p5 zu p6 ist auch vieles gleich geblieben, was es alt eingesessenen Perl 5-Programmieren sicher leichter macht Perl 6 zu lernen als anderen.
Das hier ist ein Versuch, die wichtigsten Änderungen zusammenzufassen, die häufigsten am Anfang, danach grob nach Kategorien.
Verschiedenes
use strict; ist per default angeschaltet, Ausnahme
sind Einzeiler die mit perl -e '$code' ausgeführt
werden.
Für Objektmethoden gibt es jetzt die .-Notation (anstelle
von ->), die meisten Builtins sind jetzt Methoden:
my @list; @list.push("foo"); # wie push @list, "foo" "foo".print; # wie print "foo";
Die alte Notation ist immer noch unterstützt.
Wenn man bei Methoden (also Funktionen, die zu einem Objekt gehören), die Klammern weglassen will, braucht man einen Doppelpunkt:
@list.push: 'foo';
Die print-Funktion hat eine Schwester, die ein
Newline am Ende anhängt:say (auch schon in perl 5.10
vorhanden).
my $answer = 7 * 6; # alle folgenden Varianten sind äquivalent: print $answer, "\n"; say $answer; $answer.say;
Sigils, Arrays und Hashes
Wie bisher fangen Skalare mit $, Arrays mit
@ und Hashes mit % an.
Allerdings bleibt bei Arrays und Hashes der Sigil beim Zugriff auf Elemente erhalten:
my @list = 1, 3, 5, 1, 2; my %hash = ( 'foo' => 'bar', 'baz' => 'qox', ); @list[0]; #früher: $list[0] %hash{'foo'}; #früher: $hash{'foo'} %hash<foo>; #früher: $hash{foo}
Außerdem gibt es auch noch das Sigil & für
Subroutinen, Closures und Regexes:
my $i = 1; my &func := sub { return $i++; } # und später say func;
Das Autoquoting beim Zugriff auf Hashes funktioniert in
geschweiften Klammern nicht mehr, statt dessen gibt es jetzt
<...>:
my $str = "foo"; %hash{$str}; # wie bisher %hash<foo>; # anstatt %hash{foo} %hash{'foo'}; # wie bisher
Man kann jetzt auch auf Elemente von Array- und Hashreferenzen ohne den Pfeil-Operator zugreifen:
my $a = [1, 2, [3, 4, 5], 6]; $a[0]; # früher: $a->[0] $a[2][0]; # früher $a->[0]->[0] oder $a->[0][0] my $b = { 'a' => 'b', 'c' => [1, 2, 3]}; $b{'a'}; # früher $b->{a} $b<a>; # das gleiche $b<c>[0]; # früher: $b->{c}[0] oder $b->{c}->[0]
Die Anzahl der Elemente eines Arrays bekommt man nun mit
elems:
# man beachte, dass hier keine Klammern mehr nötig sind: my @list = 1, 2, 4, 5; my $num = @list.elems; # früher: scalar @list; $num = elems @list; # das gleiche my $last_index = @list.end; # früher: $#list my $last_elem = @list[@list.end]; # früher: $list[$#list] $last_elem = @list[*-1]; # früher: $list[-1] # funktioniert immer noch: if @list < 3 { ... }
qw() wird durch <...> ersetzt und
hat auch eine interpolierende Form:
my @list = <bla blubb>; # früher: qw(bla blubb) my $str = "bla blubb"; my @l2 = <<foo $str bar>>; # liefert ['foo', 'bla', 'blubb', 'bar'];
Twigils
Globale Variablen (und ein paar andere) haben ein sekundäres Sigil, Twigil genannt:
%*ENV # früher %ENV @*ARGS # früher @ARGV $*IN, $*OUT, $ERR # früher STDIN, STDOUT, STDERR # zur Compilezeit bekannte Symbole: $?LINE # früher __LINE__ $?FILE # früher __FILE__ $?PACKAGE # früher __PACKAGE__ # Implizit deklarierte Variablen haben ein ^ als Twigl: # in absteigender Reihenfolge sortieren: sort {$^b <=> $^a}, @list # bisher: sort {$b <=> $a} @list
Kontrollstrukturen
if und unless benötigen jetzt keine
Klammern mehr um die Bedingung:
if $a < 0 { # if ($a < 0) { say "Negativ"; # print "Negativ\n"; } # }
Sollte man trotzdem Klammern verwenden, muss nach dem if
ein Leerzeichen stehen, sonst wird die Funktion namens if
aufgerufen (sofern vorhanden).
foreach und for wird zu for,
die C-artige for-Schleife zu loop:
my @nums = 1, 2, 3, 23, 42; for @nums -> $i { # tolle Berechnung mit $i hier } # Iterationsvariablen sind per Default read only. # Ändern kann man das so: for @nums -> $i is rw { # tolle Berechnung mit $i hier } # Alternativ gäbe es noch 'is copy' # über Hashes iteriern: for %hash.kv -> my $key, $val { say "$key corresponds to $val"; } # C-Style for-Schleife: loop (my $i = 0; $i < 10; $i++){ # tolle Berechnung mit $i hier }
while bleibt unverändert (außer dass es auch keine
runden Klammern mehr um die Bedingung braucht), eval { ...
} ist jetzt try { ... }.
Die Standardvariable $_
for-Schleifen ohne eine explizite Variable benutzen
auch weiterhin $_ als Standard, allerdings wird sie niemals
von Funktionen wie print als Default verwendet. Dazu braucht
man ein .print. Das gleiche gilt für Funktionen wie
uc und lc:
# früher:
for $*IN.lines { # while (<STDIN>){
.uc.say; # print uc;
} # }
Allerdings gibt es auch noch eine andere Möglichkeit: mit dem
Twigil ^ kann man Variablen mit beliebigen Namen
verwenden, und man kann sogar mehrere davon in einem einer Schleife
verwenden und damit mehrere Variablen auslesen:
for 1 .. 4 { say $^bla, ": ", $^blubb; # Ausgabe: # 1: 2 # 3: 4
Dabei wird den Variablen, die mit $^ anfangen, in
alphabetischer Reihenfolge die Werte zugewiesen:
for 1 .. 4 { say $^foo, ": ", $^bar; } # Ausgabe: # 2: 1 # 4: 3
Funktionen
Funktionen werden immer noch mit sub-Keyword
deklariert, und können jetzt Parameterdeklarationen enthalten wie in
den meisten anderen Programmiersprachen.
sub fakultaet(Int $n){ return reduce {$^a * $^b}, 1 .. $n; # reduce reduziert Listen mit der angegbenen Funktion } # immer noch möglich: sub fakultaet2 { return reduce {$^a * $^b}, 1 .. @_[0]; } # Parameter können auch beschreibbare Aliase sein: sub swap($a is rw, $b is rw){ $a, $b = $b, $a; }
Typen und ref
Perl 6 erlaubt es, Typen für Variablen zu deklarieren, es ist aber weiterhin optional. Das funktioniert auch mit selbstdeklarierten Typen, also Klassen.
my Int $ganzzahl; my Num $zahl; my Complex $complexe_zahl; my Str $string; my Str @a; # Array mit Strings my Array of Str @b # Array von Arrays mit Strings class Foo { # Defintionen hier } my Foo $foo;
Die Funktion ref gibt es nicht mehr, dafür gibt es als
Ersatz zwei Möglichkeiten:
my $str = "foo"; say $str.WHAT; # Ausgabe "Str" # Ueberprüfung, ob etwas einen bestimmten Typ hat: say "Das ist ein String" if $str ~~ Str
Die zweite Version verwendet den sogenannten Smart Match
Operator ~~, das auf für Regular Expressions
verwendet wird. Diese Form sollte man verwenden, wenn man überprüft,
ob etwas einen bestimmten Typ hat, da das auch Vererbung
berücksichtigt, d.h. sowohl [1, 2] ~~ Array als auch
[1, 2] ~~ List liefern True zurück.
Regexes
Perl 5 Regexes können in Perl 6 immer noch verwendet werden, aber es gibt auch viele Erweiterungen. Darüber gibt es eine eigene Seite: Regexes und Rules.
Strings
Strings in Perl 6 sind Unicode-Strings, die auf verschiedenen Ebenen gleichzeitig existieren können (bytes, code points, graphemes und charlingua).
Deswegen gibt es kein length mehr, weil nicht
defniert ist, was damit gemeint ist. Stattdessen kann mit
bytes die Anzahl der Bytes abfragen, mit
chars die Anzal der Zeichen , mit
codes die Anzahl der Codepoints, mit
graphs die Anzahl der Grapheme.
So haben z.B. die deutschen Umlaute in UTF-8 zwei Bytes, aber je nur ein char, code und graph.
Dagegen können z.B. Ligaturen, also aus zwei Buchstaben zusammen gesetzte Zeichen, nur ein grapheme aber zweide codepoints haben.
Wenn man mit split Strings aufspalten will, muss man die
Regex als rx/.../ übergeben:
"foo bar baz".split: rx/\s+/;
Zusätzlich gibt es comb (von "to comb", durchkämmen), das alle
Teile eines Strings zurückliefern, die auf eine regex passen - quasi
ein invertiertes split.
Mit index und rindex kann man das erste
und letzte Vorkommen eines substrings finden:
"foo".index("o"); # ist 1 "foo".rindex("o"); # ist 2
Strings werden jetzt mit ~ zusammengefügt (früher:
.), die Tilde soll zwei Arme symbolisieren, die nach den
beiden Enden der Strings greifen sollen:
my $name = "Perl"; my $version = 6; my $lang = $name ~ " " ~ $version;
Gleichzeitig erzwingt die Tilde Stringkontext:
my @a = "foo", "bar; my $str = ~@a; # "foo bar"
I/O
Aus der <$fh>-Notation zum Lesen aus Filehandles
ist $fh.lines geworden, und das Zeilenende wird jetzt
per default automatisch entfernt ("autochomp").
my $fn = "foo.txt"; my $file = $fn.open err die "Can't read '$fn': $!"; for $file.lines -> $line { # hier die Zeile verarbeiten } # oder: my $ganze_datei = $file.slurp; $file.close;
Einzelne Zeilen liefert $handle.get.
Die empfohlene Art, eine Datei zeilenweise zu lesen ist jetzt eine
for-Schleife. Und das bedeutet nicht wie in Perl 5, dass
erst die gesamte Datei gelesen wird und dann darüber iteriert wird,
sondern die Werte werden dann aus der Datei gelesen, wenn sie
gebraucht werden.
Das ist möglich, weil in Perl 6 Listen per default lazy
sind, was es auch möglich macht, unendliche Listen zu verwenden:
(1 .. *)[1].
Und so geht das Schreiben in Dateien:
my $fn = "foo.txt"; my $file = open($fn, :w) err die "Can't open '$fn' for writing: $!"; $file.say: "Erste Zeile der Datei"; # oder: say $file: "Zweite Zeile"; print $file: 'Diese Zeile hat kein \n am Ende'; $file.close;
Man beachte, dass aus print $fh $text jetzt
print $fh: $text (mit einem zusätlichen Doppelpunkt)
geworden ist, da print u.A.eine Methode der zuständigen
IO-Klasse ist.
File Tests
File test, wie z.B. -e $filename werden jetzt mit dem
Smart Match-Operator durchgeführt, und können sowohl auf Strings (als
Dateinamen) als auch auf Filehandles angewandt werden:
my $fn = "/etc/passwd"; if $fn ~~ :e { say "$fn existiert"; } else { say "Wohl kein Unix..."; }
Der :s-Filetest liefert True zurück, wenn die Datei
nicht leer ist, und im numerischen Kontext gibt er die Länge der Datei
in Byte zurück.
system und exec
system, also das Ausführen von anderen Programmen,
heißt jetzt run:
my $status = run("mutt -f /path/to/mbox"); # oder $status = run("mutt", "-f", "/path/to/mbox"); if $status { say "Mutt lief erfolgreich"; } else { say "Fehler beim ausführen von mutt, Rückgabewert: $status"; }
Der Rückgabewert, hier $status, ist im Boolean
context True, wenn das Programm 0
zurückgeliefert hat, und nicht False wie normale
Integer.
exec heißt jetzt runinstead.
Neue Features
Eine ganze Reihe neuer Features gibt es in Perl 6, die es in Perl 5 in dieser Form noch gar nicht gab.
Metaoperatoren
Metaoperatoren verwenden andere Operatoren, um sie z.B. auf Listen anzuwenden:
my @a = 1 .. 4; my $sum = [+] @a; # $sum = 10 # Aequivalent: $sum = reduce &infix:<+>, @a; $sum = reduce {$^a + $^b}, @a; $sum = reduce -> $a, $b { $a + $b }, @a; # Hyperoperatoren: my @b = <4 3 2 1> my @sum = @a »+« @b # @sum = 5, 5, 5, 5 # kann man auch als >>+<< schreiben my @b_plus_one = @b »+ 1;
Der Hyperoperator »...« wendet den Operator in der
Mitte paarweise auf die Elemente zweier Listen an. Wenn man auf einer
Seite keine Liste sondern einen Skalar angibt, muss man die
entsprechende Hälfte des Hyperoperators weglassen.
Anstatt der Unicode-Zeichen » und « kann
man auch doppelte Kleiner- und Größerzeichen
>>...<< benutzen.
Hyper- und Reduktionsoperator führen ihre Operationen auf Multi-Prozessor-Systemen parallelisiert aus, wenn der Interpreter bzw. Compiler entsprechend konfiguriert wird.
Verschiedenes (2)
wantarray wird want
Die Funktion wantarray ist dem allgemeineren
want-Builtin gewichen.
Die alte Funktionalität bekommt man mit want.list oder
alternativ want ~~ List.
Allgemein kann man mit want ~~ $typ abfragen, ob der
Aufrufer den Typ $typ erwartet, und mit
want.count. Mehr dazu im Abschnitt Kontexte.
Data::Dumper
Data::Dumper ist jetzt überflüssig, dafür gibt es die
eingebaute Methode perl:
my %foo = "a" => "b", "c" => <d e f>; say %foo.perl; #Ausgabe: {("a" => "b"), ("c" => ("d", "e", "f"))}
perl gibt Perl-Code aus, der das entsprechende
Konstrukt erzeugt.
Ausführen anderer Programmiersprachen
Mit eval können jetzt auch andere Programmiersprachen
ausgeführt werden, insbesondere Perl 5, aber auch Yaml (liefert dann Datenstrukturen
zurück), und je nach Compiler/Interpreter eventuell Java, Haskell,
Ruby und andere:
eval("/* Java-Code hier, der einen Wert liefert */", :lang(Java));
Die Flexibilität der Datenstrukturen, die von der "Fremdsprache" zurückgegeben werden können, hängt sicher von der entsprechenden Sprache und dem Interface ab, aber zumindest Perl 5 sollte beliebig komplexe Datenstrukturen (inklusive Objekte) zurückliefern können.
Pointy Blocks
Pointy Blocks sind eine neue Möglichkeit, anonyme Codeblöcke zu schreiben:
my $square = -> $a { $a * $a }; say $square(4); # Ausgabe: 16 say $square.WHAT # Ausgabe: Block
Man beachte, dass die for-Schleife, wie sie vorher
vorgestellt wurde, eine pointy block benutzt:
for 1 .. 5 -> $a { say $a; }
Alternativ können auch self declaring formal parameters
verwendet werden, also Variablen mit dem $^-Sigil:
for 1 .. 5 { say $^number; }