Sandra Schlichting
Sandra Schlichting

Reputation: 25996

What to use instead of Smartmatch?

I just upgraded to Perl 5.26.1, now I get

Smartmatch is experimental at check_tr.pl line 67.

where the code in question is

my @patterns = (qr/summary:\s+(.+?) in\s+(.+?) - average of\s+(.+?)$/,
        qr/summary:\s+(.+?) in\s+(.+) (.+? .+?)$/);
my $r = "";
opendir(DIR, $dir) or die $!;
while(my $file = readdir(DIR)) {

    next if ($file =~ m/^\./);
     open(F, '<', "$dir/$file") or die $!;

     if (<F> ~~ @patterns) {
         $r .= <F>;
...

Question

Ideally with as few changes to the code as possible. What should I do instead of smart matching?

Upvotes: 8

Views: 7832

Answers (4)

dami
dami

Reputation: 180

For situations where you have several shapes of data to compare with, and you don't want a long list of if / elsif in your code to go over all possible situations, then the match::simple module by TOBYINK is a pretty good replacement for the old smartmatch.

Upvotes: 0

Gonen
Gonen

Reputation: 4075

Have to agree with the other answers that Perl's smartmatch is better avoided.

There is a list of alternatives (with examples) on Perl-Monks site:
PerlMonks - Smartmatch alternatives

Upvotes: 2

tjd
tjd

Reputation: 4104

The reason Smartmatch is experimental is that it is so hard to figure out what it will do without referencing the Docs. Even so, how do we interperet the above code?

Is this a case of:

ARRAY1    ARRAY2     recurse on paired elements of ARRAY1 and ARRAY2[2]
            like: (ARRAY1[0] ~~ ARRAY2[0])
                    && (ARRAY1[1] ~~ ARRAY2[1]) && ...

Where we presume <F> is interpreted in list context and emptied in a single call?

Or is this a case of:

 Any       ARRAY      smartmatch each ARRAY element[3]
            like: grep { Any ~~ $_ } ARRAY

I'm going to guess the 2nd. In which case the snippet above from the docs gives you an excellent (and clearer) coding alternative. Presuming @patterns contains regexes, you can also replace the ~~ with =~.


If you don't like the grep alternative from the docs, I'd recommend looking into either List::Util or List::MoreUtils. Both contain an any call which acts as a short-circuiting grep. Alternatively, if you are trying to implement the ARRAY1 ARRAY2 option, the later library contains a pairwise call that may serve.

Upvotes: 6

amon
amon

Reputation: 57630

Just spell out what you mean. E.g. if you want to check whether the header line matches any regex in @patterns:

use List::Util 'any';
...
my $line = <F>;
if (any { $line =~ $_ } @patterns) { ... }

Though in that case, it might be more sensible to pre-compile a single pattern such as:

my ($pattern) = map qr/$_/, join '|', @patterns;
...
if (<F> =~ $pattern) { ... }

If your @patterns array contains different kinds of data, you might want to choose a different matching operator, e.g. == or eq. If the @patterns are not all the same “type” and you really want the smartmatch behaviour, you can silence the warning and continue to use it:

use experimental 'smartmatch';

However, this might then break without further warnings in the future.

Upvotes: 9

Related Questions