Smart-match

[ Perl tips index ]
[ Subscribe to Perl tips ]

Perl 5.10 introduces a new-operator, called smart-match, written ~~. As the name suggests, smart-match tries to compare its arguments in an intelligent fashion. Using smart-match effectively allows many complex operations to be reduces to very simple statements.

Unlike many of the other features introduced in Perl 5.10, there's no need to use the feature pragma to enable smart-match, as long as you're using 5.10 it's available.

The smart-match operator is always commutative. That means that $x ~~ $y works the same way as $y ~~ $x. You'll never have to remember which order to place to your operands with smart-match.

Smart-match in action.

As a simple introduction, we can use smart-match to do a simple string comparison between simple scalars. For example:

    use feature qw(say);
    my $x = "foo";
    my $y = "bar";
    my $z = "foo";
    say '$x and $y are identical strings' if $x ~~ $y;
    say '$x and $z are identical strings' if $x ~~ $z;    # Printed

If one of our arguments is a number, then a numeric comparison is performed:

    my $num   = 100;
    my $input = <STDIN>;
    say 'You entered 100' if $num ~~ $input;

This will print our message if our user enters 100, 100.00, +100, 1e2, or any other string that looks like the number 100. We can also smart-match against a regexp:

    my $input  = <STDIN>;
    say 'You said the secret word!' if $input ~~ /xyzzy/;

Smart-matching with a regexp also works with saved regexps created with qr{}.

So we can use smart-match to act like eq, == and =~, so what? Well, it does much more than that. We can use smart-match to search a list:

    my @friends = qw(Frodo Meriadoc Pippin Samwise Gandalf);
    my $name    = <STDIN>;
    chomp($name);
    say "You're a friend" if $name ~~ @friends;

It's important to note that searching an array with smart-match is extremely fast. It's faster than using grep, it's faster than using first from Scalar::Util, and it's faster than walking through the loop with foreach, even if you do know all the clever optimisations.

We can also use smart-match to compare arrays:

    my @foo = qw(x y z xyzzy ninja);
    my @bar = qw(x y z xyzzy ninja);
    say "Identical arrays" if @foo ~~ @bar;

And even search inside an array using a string:

    say "Array contains a ninja " if @foo ~~ 'ninja';

or using a regexp:

    say "Array contains magic pattern" if @foo ~~ /xyz/;

Smart-match works with array references, too:

    my $array_ref = [5, 10, 15];
    say "Array contains 10" if $array_ref ~~ 10;

Of course, we can use smart-match with more than just arrays and scalars, it works with searching for the key in a hash, too!

    my %colour = (
        sky   => 'blue',
        grass => 'green',
        apple => 'red',
    );
    my $input = <STDIN>;
    chomp $input;
    say "I know the colour of $input" if $input ~~ %colour;
    say "A key starts with 'gr'" if %colour ~~ /^gr/;

You can even use it to see if the two hashes have identical keys:

    my %taste = (
        grass => 'boring',
        apple => 'yummy',
        sky   => undef,
    );
    say 'Hashes have identical keys' if %taste ~~ %colour;

You can even overload the smart-match operator to define what constitutes 'smart' for a given class of objects, although doing so is beyond the scope of this tip.

Further reading

You can learn more about smart-match in the Smart matching in detail section of perldoc perlsyn if you have Perl 5.10 installed, or you can read about it on-line at http://search.cpan.org/~rgarcia/perl-5.10.0/pod/perlsyn.pod#Smart_matching_in_detail.

[ Perl tips index ]
[ Subscribe to Perl tips ]


This Perl tip and associated text is copyright Perl Training Australia. You may freely distribute this text so long as it is distributed in full with this Copyright noticed attached.

If you have any questions please don't hesitate to contact us:

Email: contact@perltraining.com.au
Phone: 03 9354 6001 (Australia)
International: +61 3 9354 6001

Valid XHTML 1.0 Valid CSS