So how about that smartmatch?

Hi p5p!

We have long been wondering what to do about smartmatch, how to fix it,
how to make it useful. Atleast I have. The main flaws in my opinion are
as follows:

  1. It has way too many different argument variants that do different
     things. In other words: It's too smart.
  2. It doesn't have a numeric and a stringy variant. In other words:
     It's not perly.

What I mean by the first issue should be obvious. Just look at the tables
in perldoc perlop [1] ... it has way too many ways that it can operate.

The second issue is one that hasn't been discussed as much as the first
one. Practically all perl comparison operators come in two variants:
numeric comparison and stringy comparison. This is how types work in perl.
The operator you use determines which type of values you want to operate

  * 'eq', 'ne', cmp' for stringy, '==', '!=', '<=>' for numeric.
  * 'le', 'lt', 'ge', 'gt' for stringy, '<=', '<', '>=', '>' for numeric.

In perl6/raku it's completely different. They have typed variables instead.
That's why their smartmatch works for them, and doesn't for perl.

As for why this is a problem, consider the following snippet:

  my @numbers = (0 .. 10);
  if ("0 but true" ~~ @numbers) { print "matches" }

Now this, perhaps surprisingly, prints "matches".
How about the following?

  my @numbers = ('0' .. '10');
  if ("0 but true" ~~ @numbers) { print "matches" }

Do we get "matches" printed out again? No we don't. The difference is because
the first snippet stored the elements of @numbers internally as integers,
while the second one stored them internally as strings, and smartmatch cares
about this. This is not perly.

I'd like to propose that we completely change how smartmatch works. The most
useful (at least to me) and what I suspect to be the most common way that it's
used currently is like this:


Now, this is not one of the actual options in the table mentioned above. The
table tries too hard to make perl variables typed, so it calls it "Any ~~ ARRAY"

Currently "Any ~~ ARRAY" is documented as being equivalent to:
"grep { Any ~~ $_ } ARRAY", which re-involves smartmatch again. Since I'm
proposing to do away with all the different operating modes of smartmatch this
can't continue to work anymore.

My suggestion is that it would work like a numeric 'any' from List::Util, so
would mean
  any { SCALAR == $_ } LIST

We would also add a new stringy variant of the operator which I'd like to name
'in', like this:
which would mean
  any { SCALAR eq $_ } LIST

The reason I'm choosing '~~' for numeric matching and proposing 'in' for stringy
matching is because all the other comparison operators have that kind of naming
scheme for numeric and stringy variants.

This would in my opinion make smartmatch (... well, less smart for one thing, so
it might need to be renamed) useful again.


As for 'given'/'when', it should no longer use smartmatch at all. There's no way
for it to have both string and numeric variants that would fit well. The 'when'
condition should be its own thing, and hopefully not using the same semantics as
the old smartmatch. An example replacement is Switch::Plain [2] which does have
separate string and numeric variants.


I'd suggest something along the lines of the following as a path forward:

  1. Deprecate [3] smartmatch in 5.30.
  2. Remove smartmatch in 5.34.
  3. Introduce a new smartmatch [4] either directly in 5.34, or wait until 5.36.
  4. ???
  5. Profit.

  -- Best regards / Andreas "pink_mist" Guldstrand

[3] Even though it's experimental and shouldn't need deprecation, it's still in
    too widespread use to just remove it.
[4] Whether this variant or a different one.
12/31/2018 9:20:25 PM
perl.perl5.porters 47662 articles. 1 followers. Follow

0 Replies

Similar Articles

[PageSpeed] 24