Matching simply

A little over ten years ago, when Perl 5.18 was approaching its release date, I released match::simple. This was mostly in response to the smartmatch operator (~~) being deprecated, but also a solution to the incredibly arcane rules for how the smartmatch operator operated.

match::simple was intended to be... simpler. The operator looks a little funky because it uses some clever trickery to fake being an infix operator:

    use match::simple;
    
    if ( $this |M| $that ) {
        ...;
    }

For those who don't like the infix syntax, a regular function is also provided:

    use match::simple 'match';
    
    if ( match $this, $that ) {
        ...;
    }

Its behaviour was always determined by the operand on the right-hand side. Given:

    $a |M| $b
  • If $b is undef, $a only matches if it's also undef.
  • If $b is any other non-reference value, acts like the string equality (eq) operator.
  • If $b is a regexp, acts like the regexp binding (=~) operator.
  • If $b is a coderef, $a matches if $b->($a) returns true.
  • If $b is an object, $a matches if $b->MATCH($a) returns true or $a ~~ $b using ~~ operator overloading.
  • If $b is an arrayref, $a matches if $a |M| $_ for any element of @{$b}.
  • If $b is anything else, the operator croaks.

These seemed simple, sane, and predictable. Yes, some form of numeric matching would have been nice, but I ruled that out because of the ambiguity of numeric strings.

Plus because if you really need numeric matching, I knew you could wrap the number in a coderef:

    if ( $a |M| sub { $b == shift } ) {
        ...;
    }

Type::Tiny has always been compatible with match::simple. You can use:

    use match::simple;
    use Types::Standard -types;
    
    if ( $value |M| ArrayRef ) {
        ...;
    }
    elsif ( $value |M| HashRef ) {
        ...;
    }

Anyway, fast forward to now, and Perl 5.38 has now been released, which finally removes the long-deprecated smartmatch operator. Thankfully one of the new features it also provides allows for true user-defined infix operators!

Introducing Syntax::Operator::Matches!

    use Syntax::Operator::Matches;
    
    if ( $this matches $that ) {
        ...;
    }

This uses exactly the same logic as match::simple — logic that has been frozen since 2013, but finally has beautiful syntax.

You can do nice things like:

    use Syntax::Operator::Matches;
    use Types::Standard -types;
    
    if ( $value matches ArrayRef[Int] ) {
        ...;
    }
    elsif ( $value matches Str|Undef ) {
        ...;
    }

Some of it is just a wrapper around match::simple, but other parts happen purely in XS, so operate much faster.

If you're looking for something to replace smartmatch in your code, consider Syntax::Operator::Matches. If you need backwards compatibility, match::simple is still here and isn't going to disappear.

2 Comments

Nice, looks ideal for Olaf's advent calendar.

I agree. Looks like it builds on your Sub::Infix, which I think is a great module. I encourage everyone to study its implementation.

Leave a comment

About Toby Inkster

user-pic I'm tobyink on CPAN, IRC and PerlMonks.