Mini HowTo: How to port Perl 5 modules to Perl 6 - Other resources: http://pugs.kwiki.org/?ConversionGuide http://perlmonks.org/index.pl?node_id=442402 - Before you start porting a module, make sure you understand the class hierarchy of that module. It helps if you've actually used that module in Perl 5 :) - Port a module even if it depends on some other (not yet ported) modules -- the dependencies can be ported later on. - Often, the translation of P5 -> P6 is quite mechanic: - $array[idx] -> @array[idx] - @array[1,2,3] -> @array[1,2,3] - $hash{$key} -> %hash{$key} - $hash{word} -> %hash - @hash{'a','b','c'} -> %hash - "@array" -> "@array[]" - "%hash" -> "%hash{}" - scalar @foo -> +@foo # or @foo.elems - a ? b : c -> a ?? b !! c - $self->method(...) -> self.method(...) or $.method(...), @.method(...)... - sub { my ($self, $a, $b) = @_; ... } -> method ($a, $b) { ... } - $x =~ s/.../.../g -> $x ~~ s:P5:g/.../.../ - $self->{foo} -> $.foo - $foo = "bar" unless defined $foo -> $foo //= "bar" # (//) and (//=) will be in 5.9, too, IIRC - if($foo eq "a" or $foo eq "b" or $foo eq "c") {...} -> if $foo eq "a"|"b"|"c" {...} - foreach my $foo (@baz) {...} -> for @baz -> $foo {...} - length("foo") -> "foo".chars - Regular expressions: m/ a * b /x -> m/ a * b / # /x now default m/ a\ b /x -> m/ a\ b / m/ a b / # also see below m:s/ a b / # :s == :sigspace (space) -> # or \c[SPACE], \x20, \040, # <' '> [abc] -> <[abc]> [^abc] -> <-[abc]> [abc ] -> <[ abc\ ]> # ws meta in <[...]> too (?:...) -> [...] < > -> \< \> \p{prop} -> \P{prop} -> <-prop> \Qstring\E -> <{ quotemeta 'string' }> # or <'literal string'> \Q$var\E -> $var # always literal $var -> <$var> \A -> ^ \z -> $ \Z -> \n?$ \n -> \c[LF] # specifically a linefeed \r?\n -> \n # logical newline [^\n] -> \N # not a logical newline \C[LF] # not a linefeed . -> \N # no /s . -> . # /s \G -> <( .pos == $oldpos )> m:p/pat/ \a -> \c[BEL] \N{CENT SIGN} -> \c[CENT SIGN] [^\N{CENT SIGN}] -> \C[CENT SIGN] \c[ -> \e \cX -> \c[^X] [^\t] -> \T [^\r] -> \R [^\f] -> \F [^\e] -> \E [^\x1B] -> \X1B [^\x{263a}] -> \X[263a] \1 -> $1 /$1/ -> my $old1 = $1; /$old1/ // -> // or // /a|/ -> /a|/ \C -> [:bytes .] # forced byte in UTF-8 (not # recommended) \X -> <.> # single grapheme [:graphs .] x{2} -> x**{2} x{2,} -> x**{2...} x{1,2} -> x**{1..2} x{1,2}? -> x**{1..2}? (?=foo) -> (?!foo) -> (?<=foo) -> (? (?{...}) -> {...} (??{...}) -> <{...}> (?>\d*) \d*: # single atom no backtrack (?>(\d*)) (\d*): # () is still single atom (?>...) [...]: # multiple atoms need [] (?(c)t|f) [ c :: t | f ] s/foo/bar()/e -> s/foo/{ bar() }/ m/^foo$/s -> m/^foo$/ m/^foo$/m -> m/^^foo$$/ m?foo? -> m:once/foo/ - split(m/;/, $foo) -> split(/;/, $foo) # notice: no m m// now works immediately, so: split(m/;/, $foo); would use the return value of the match (on the implicit $_) as the delimiter. - Or, if you don't want to split on a regular expression: split(m/;/, $foo) -> split(";", $foo) - split(' ', $foo) -> words($foo) or $foo.words or «$foo» - Heredocs: < qq:to/END/ <<"END" -> qq:to/END/ <<'END' -> q:to/END/ - You can normally remove all that Perl 5 argument parsing and simply replace it with a nice signature. - # Perl 5 require Exporter; our @ISA = qw< Exporter >; our @EXPORT = qw< foo >; sub foo { ... } # -> Perl 6 sub foo(...) is export { ... } - return map {.4.} sort {.3.} grep {.2.} map {.1.} -> map {.1.} ==> grep {.2.} ==> sort {.3.} ==> map {.4.} ==> return - The Perl 6 translation of Perl 5's getter/setter idiom is especially cool: # Perl 5 sub get_foo { my $self = shift; my $ret = $self->{foo}; return lc $ret; # always normalize } sub set_foo { my ($self, $to) = @_; $to =~ s/\s+$//; # strip whitespace at the end $self->{foo} = $to; } # -> Perl 6 (see L for information about Proxy) has $!foo; method foo() is rw { return new Proxy: FETCH => { lc $!foo }, STORE => -> $to is copy { $to ~~ s/\s+$//; $!foo = $to; }; } # And then: say $obj.foo; $obj.foo = "..."; # Notice: Standard assignment syntax! # Assignments should look like assignments, not like # method calls - If you trust the user to give appropriate data to the accessors, you can also use: has $.foo is rw; - Or: subset OddInt of Int where { $^n % 2 == 1 } has OddInt $.foo is rw; # And then: $obj.foo = 12; # will die - Arrays in item context become references to themselves, e.g.: my @bar = (1, "a", 3, "b") my $foo = @bar; # $foo now contains a reference to @bar $foo[1]; # == "a" Hashes behave in the same way: my %bar = (a => 1, b => "baz"); my $foo = %bar; # $foo now contains a reference to @bar $foo; # == "baz" - Methods and properties generally belong to the object contained, not the container: my @bar = (1, 2, 3, 4); my $foo = @bar; $foo.elems; # == 4 (@bar.elems) but tied($x)->foo -> variable($x).foo also non-scalar container objects are accessed directly: @bar.elems - When calling a method, parentheses are required on the dot notation if there are any arguments. There may be no space between the method name and the left parenthesis unless you use the dot form of parentheses: .doit # okay, no arguments .doit() # okay, no arguments .doit () # ILLEGAL (two terms in a row) .doit.() # okay, no arguments, same as .doit() .doit .() # okay, no arguments, same as .doit() But a colon may stand in for a left paren with no corresponding right: .doit: 1,2,3 # okay - Subroutine/method/array/hash access: whitespace is disallowed between the name and the opening brace. The "dot form" can be used to introduce intervening space. foo(@args) # ok foo.(@args) # ok foo (@args) # WRONG foo .(@args) # ok @a[0] # ok @a.[0] # ok @a [0] # WRONG @a .[0] # ok %h{'k'} # ok %h.{'k'} # ok %h {'k'} # WRONG %h .{'k'} # ok %h # ok %h. # ok %h # WRONG %h . # ok - open() open my $fh, "<", $filename or die $!; -> my $fh = open($filename, :r) err die $!; "<" -> :r ">" -> :w ">>" -> :a '+<" -> :rw mixing them does not work yet open(FH, $filename) -> our $fh = open($filename) my $fh = open($filename) and possibly: sub FH () { $fh } macro FH () { q:code { $fh } } but $fh generally preferred - print to file print $fh "Hello\n"; -> print $fh, "Hello\n"; # adding the comma or -> $fh.print("Hello\n"); -> $fh.print: "Hello\n"; -> print $fh: "Hello\n"; - close the file close($fh); -> the same or $fh.close; - reading from a file $fh.readline =$fh