Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Perl Features

A few pages about features introduced in certain version of Perl.

Some of these features have changed or were removed since then.

Advanced Features in 5.10

Advanced Features

When there is an uninitialized value, 5.10 will include the name of the variable in the warning.

defined or

  • //
  • defined-or

How do you set a default value of a scalar?

$x = defined $x ? $x : $DEFAULT;

$x ||= $DEFAULT;

$x //= $DEFAULT;
#!/usr/bin/perl
use strict;
use warnings;

my $val;
print defined $val ? "defined\n" : "not defined\n";   # not defined

$val //= 42;

print "$val\n";   # 42



$val = 0;

print "$val\n";   # 0

$val //= 42;

print "$val\n";   # 0

Turn on features explicitly

  • feature
  • v5.10
use feature qw(say);
use feature qw(:5.10);
use 5.010;
use v5.10;

say

  • say
#!/usr/bin/perl 
use strict;
use warnings;

use feature qw(say);

my $hello = "Hello world";

say $hello;

feature is a lexical pragma

{
    use feature qw(say);
    say $var;
}
print "Cannot use say here\n";

static variable (with scope)

  • static
#!/usr/bin/perl 
use strict;
use warnings;

{
   my $counter = 0;
   sub next_counter {
      $counter++; 
      return $counter;
   }
}

print next_counter(), "\n";
print next_counter(), "\n";

state variable

  • state
  • static

In Perl 5.10 the state keyword was added that allows us to create a static variable. When we declare such variable in a function the declaration and the initialization takes places only once no matter how many times the function is called. Instead of being initialized every time we enter the function like a variable declared with my would do, state variables are initialized only once and then they remember their value for the subsequent calls to the same function.

#!/usr/bin/perl 
use strict;
use warnings;

use 5.010;

sub next_counter {
    state $counter = 0;
    $counter++;
    return $counter;
}


say next_counter();
say next_counter();
say next_counter();
1
2
3

regex: Named capture buffers

  • %+
  • %-
#!/usr/bin/perl 
use strict;
use warnings;

use 5.010;

my @data = (
    "line 100 long ",
    "we have a number 42 here ",
);

foreach my $line (@data) {
    if ($line =~ m/(\d+)/) {
        print "number: $1\n";
    }

    if ($line =~ m/(?<number>\d+)/) {
        print "number: $+{number}\n";
    }

    if ($line =~ m/((?<str>\w+)\s+)*/) {
        print "str: $+{str}\n";
        print "str all: @{$-{str}}\n";
        print "all: $&\n";
    }

    if ($line =~ m/(?<str>\w+)\s+(?<str>\w+)/) {
        print "2 str: $+{str}\n";
        print "2 str all: " . join(",", @{$-{str}}) . "\n";
        print "2 all: $&\n";
    }

    if ($line =~ m/(?<str>\w+) .* \k<str> /x) {
        print "Matched $+{str}   in '$&'\n";
    }
}



__END__
my @data = (
    "engine = Thomas",
);

foreach my $line (@data) {
    if ($line =~ m/(\w+)\s*=\s*(\w+)/) {
        print "Field=$1,  value=$2\n";
    }
    if ($line =~ m/(?<field>\w+)\s*=\s*(?'value'\w+)/) {
        print "Field=$+{field},  value=$+{value}\n";
    }
}

See also the values in these two hashes:

%+  hash contains the left most match with the given name
%+{name}

%-  hash contains and array of the matches
%-{name}[0]

Possessive quantifier

  • ++
#!/usr/bin/perl
use strict;
use warnings;

use 5.010;

say ("aaa" =~ / a+   a /x  ? 'YES' : 'NO');  # matched
say ("aaa" =~ / a++   a /x ? 'YES' : 'NO');  # does NOT match

Mainly for speed improvements

smartmatch ~~ - Don't use it!

~~ compares values as strings
unless there is a better way to compare them

So it can do things like

"Foo" ~~ "Foo"
42    ~~ 42
42    ~~ 42.0
42    ~~ "42.0"
42    ~~ "23"

And even

$name    ~~ @people
@people  ~~ $name
$name    ~~ %phonebook
$name    ~~ qr/regex-perl/

~~ decides how to compare based on the values

perldoc perlsyn Smart matching in detail

$a      $b        Type of Match Implied    Matching Code
======  =====     =====================    =============
(overloading trumps everything)
Code[+] Code[+]   referential equality     $a == $b
Any     Code[+]   scalar sub truth         $b->($a)
Hash    Hash      hash keys identical      [sort keys %$a]~~[sort keys %$b]
Hash    Array     hash slice existence     grep {exists $a->{$_}} @$b
Hash    Regex     hash key grep            grep /$b/, keys %$a
Hash    Any       hash entry existence     exists $a->{$b}
Array   Array     arrays are identical[*]
Array   Regex     array grep               grep /$b/, @$a
Array   Num       array contains number    grep $_ == $b, @$a
Array   Any       array contains string    grep $_ eq $b, @$a
Any     undef     undefined                !defined $a
Any     Regex     pattern match            $a =~ /$b/
Code()  Code()    results are equal        $a->() eq $b->()
Any     Code()    simple closure truth     $b->() # ignoring $a
Num     numish[!] numeric equality         $a == $b
Any     Str       string equality          $a eq $b
Any     Num       numeric equality         $a == $b
Any     Any       string equality          $a eq $b

Smart match example - Don't use it!

#!/usr/bin/perl 
use strict;
use warnings;

use 5.010;

sub compare {
    my ($x, $y, $d) = @_;
    my $t = ($x ~~ $y ? "True" : "False");
    $x //= '';
    $y //= '';
    printf("%-4s ~~ %-4s is %-5s   (%s)\n", $x, $y, $t, $d);
}

compare("Foo", "Foo", "Any ~~ Any    =>   eq");
compare("Foo", "Bar", "Any ~~ Any    =>   eq");
compare(42, 42,       "Any ~~ Num    =>   ==");
compare(42, 42.0,     "Any ~~ Num    =>   ==");
compare(42, "42x",    "Any ~~ Str    =>   eq");
compare(42, "42",     "Any ~~ numish =>   ==");
compare(42, "42.0",   "Any ~~ numish =>   ==");
#compare(42, "42\n",   "Any ~~ numish =>   ==");
compare(42, "42 ",    "Any ~~ numish =>   ==");

compare("42", "42.0",   "numish ~~ numish =>   eq");

compare(42, undef,      "Any ~~ undef =>   defined ?");
compare(undef, undef,   "Any ~~ undef =>   defined ?");

compare("Moose", [qw(Foo Bar Baz)],       "Str ~~ Array");
compare("Moose", [qw(Foo Bar Moose Baz)], "Str ~~ Array");

# And of course if the individual value is a number then
# each individual element of the array is checked using ==
compare(42, [23, 17, 70],          "Num ~~ Array");
compare(42, [23, 17, 42, 70],      "Num ~~ Array");

compare(42, [23, 17, "42\n", 70],  "Num ~~ Array");
compare(42, [23, 17, "42 ", 70],   "Num ~~ Array");
#compare(42, [23, 17, "42x", 70],  "Num ~~ Array");
# this generates a warning when trying to == "42x"

# If there can be an array reference then we can also have a HASH reference there
# The smart match will check if the given scalar is one of the keys in the hash
# That is using exists
compare('a', {a => 19, b => 23},    "Str ~~ HASH");
compare(42, {a => 19, b => 23},     "Num ~~ HASH");

# The obvious question then what happens when both sides are 
# complex data structures (Arrays or Hashes?)

# With Arrays, it check if each element is the same
compare(["Foo", "Bar"], ["Foo", "Bar"],          "Array ~~ Array");
compare(["Foo", "Bar"], ["Foo", "Bar", "Baz"],   "Array ~~ Array");
compare([1,2,3], [1,2,3],                        "Array ~~ Array");


compare({Foo => 19, Bar => 23}, {Foo => 23, Bar => 19}, "Hash ~~ Hash");


compare(["Foo", ["Bar", "Baz"]],
    ["Foo", ["Bar", "Baz"]], 
    "Complex Array ~~ Complex Array");



compare("Perl 5.10", qr/Moose/, "Str ~~ Regex");
compare(qr/Moose/,  "Perl 5.10", "Regex ~~ Str");
compare("Perl 5.10", qr/Perl/, "Str ~~ Regex");
compare(qr/Perl/,  "Perl 5.10", "Regex ~~ Str");
say /Perl/ ~~ "Perl 5.10" ? "T" : "F";


# Side note, instead of reference to Array or reference to Hash
# you can actually put there
# the real Array or the real Hash (but not a simle list) so
# this works:
my @a = (2, 3);
say 3 ~~ @a ? "T" : "F";

# but this does not:
#say 3 ~~ (2, 3) ? "T" : "F";

#my @m = ([ 2, 3], [4, 5]);
#say 3 ~~ @m ? "T" : "F";

say 1 ~~ \&true ? "T" : "F";
say 0 ~~ \&true ? "T" : "F";

# There are more complex cases as well but let's get back now to the scalars
# We can have other values in scalars as well, eg, regular expressions and 

sub true {
    return $_[0];
}
__END__
{
    my $x = 42;
    my $y = "42";
    
    say "Compare $x and $y";
    if ($x == $y) {
        say "== Same numbers";
    }
    if ($x ~~ $y) {
        say "~~ Same numbers";
    }
}

{
    my $x = 42;
    my $y = "42.0";
    
    say "Compare $x and $y";
    if ($x == $y) {
        say "== Same numbers";
    }
    if ($x ne $y) {
        say "ne Different strings";
    }
    if ($x ~~ $y) {
        say "~~ Same numbers";
    }
}

{
    my $x = 42;
    my $y = "42x";
    
    say "Compare $x and $y";
#    if ($x == $y) {
#        say "== Same numbers";
#    }
    if ($x ne $y) {
        say "ne Different strings";
    }
    if ($x ~~ $y) {
        say "~~ Same numbers";
    }
}


switch - Don't use it!

  • switch
  • case
  • given
  • when
#!/usr/bin/perl 
use strict;
use warnings;

use 5.010;

my $value = <STDIN>;
chomp $value;

given($value) {
    when(3) { say "Three"; }
    when(7) { say "Seven"; }
    when(9) { say "Nine"; }
    default { say "Non of the expected values"; }
}

given($value) {
    when(/^\d+$/)            { say "digits only"; }
    when(/^\w+$/)            { say "Word characters"; }
    when(/^[a-zA-Z0-9.-]+$/) { say "Domain namish"; }
    default { say "Non of the expected"; }
}


given($value) {
    when(10) {
        say "Number 10";
    }
    when([11, 23, 48]) {
        say "In the list";
    }
    when($_ < 21) {
        say "under 21";
    }
    when(/^\d+$/) {
        say "digits only";
    }
    when(\&is_number) {
        say "Is number";
    }
    default {
        say "None of the above";
    }
}

sub is_number {
    return $_[0] =~ /\d/ and $_[0] =~ /^[+-]?\d*\.\d*$/;
}

New features in 5.12

Perl 5.12 features

  • Y2038 compliance
  • Pluggable Keywords
  • configure_requires in CPAN module meta data (META.yml)
  • deprecations warn by default

Implicit stricture

  • v5.12

no need to write use strict any more

use v5.12;
$x = 23;
say $x;
Global symbol "$x" requires explicit package name at a.pl line 3.
Global symbol "$x" requires explicit package name at a.pl line 4.
Execution of a.pl aborted due to compilation errors.

use parent

  • parent
use parent qw(Foo Bar);

use parent instead of base

package NAME VERSION

  • package Foo v5.12
package Foo 1.00;

Yada Yada Operator...

  • ...
  • Yada Yada
sub new {
   ...
}
Unimplemented at Foo.pm line 5.

each on arrays

  • each
while (my ($index, $value) = each @a) {
   say "$index $value";
}
0 a
1 b
2 c

delete local

  • delete local
my %h = (foo => 'bar');
say exists $h{foo} ? 1 : 0;
{
   delete local $h{foo};
   say exists $h{foo} ? 1 : 0;
}
say exists $h{foo} ? 1 : 0;
1
0
1