Matching simply
Tags: perl, smartmatch
Published: 2023-07-14 20:49:11

---
title: Matching simply
published: true
date: 2023-07-14 20:42:30 UTC
tags: Perl,smartmatch
canonical_url: https://toby.ink/blog/2023/07/14/matching-simply/
---

A little over ten years ago, when Perl 5.18 was approaching its release date, I released [match::simple](https://metacpan.org/pod/match%3A%3Asimple). 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:

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

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

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

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

```perl
    $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:

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

[Type::Tiny](https://metacpan.org/pod/Type%3A%3ATiny) has always been compatible with [match::simple](https://metacpan.org/pod/match%3A%3Asimple). You can use:

```perl
    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](https://metacpan.org/pod/Syntax%3A%3AOperator%3A%3AMatches)!

```perl
    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:

```perl
    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](https://metacpan.org/pod/Syntax%3A%3AOperator%3A%3AMatches). If you need backwards compatibility, [match::simple](https://metacpan.org/pod/match%3A%3Asimple) is still here and isn't going to disappear.