While, on paper, Perl’s “smart matching” operator was the best thing since sliced bread, in reality it’s not all it’s cracked up to be.

My main issue with smart matching, often referred to as the operator symbol ~~, that it doesn’t coerce some things to the type one expects. ~~ has the nice feature that you can essentially feed anything into either side and it produces a fairly sensible answer: for instance,

my @types = qw(js css img);
my $type = 'js';
$type ~~ @types; # => true

— in this case, because 'js' is in the array ['js','css','img'] that is implicitly produced by the qw on L1. Or, even,

my %types = (
    'js' => "JavaScript",
    'css' => "Cascading Style Sheets",
    'img' => "Images",
my $type = 'js';
$type ~~ %types; # => true

But if you didn’t already know that _Any_ ~~ _Hash_ matched against the keys, you might consider:

$type ~~ keys %types; # => error
# Argument "js" isn't numeric in smart match at (…) line 5.

Which is counter-intuitive. What does keys %types return? To my eyes, an Array, right? qw(…) does, too, right?

(23:52) Uh, no: qw and keys both return lists, which aren’t very equivalent to arrays. It just so happens that most people store lists in arrays, or query lists like arrays.

Well, apparently not. A huge hint is that is says “argument isn’t numeric” which suggests that ~~ has switched into numeric equality mode. Under what circumstances does an Array become a Num? In the scalar context, of course.

(23:54) That may be true for Arrays, but not for lists.
(23:57) Theoretically, under no circumstances can this happen.

We’ve all seen things like these three functionally-equivalent lines:

die 'usage: $0 […] […]' unless @ARGV == 2;
die 'usage: $0 […] […]' unless scalar @ARGV == 2;
die 'usage: $0 […] […]' unless $#ARGV == 2;

The array @ARGV is, of course, forced into scalar form to count its length — it’s one of Perl’s nice sigilic, and in the last case, twigilic, tricks.

Now, that’s all well and good: operands are permitted to coerce types. Except ~~. From perlop:

[Smartmatching] is also unique in that all other Perl operators impose a context (usually string or numeric context) on their operands, autoconverting those operands to those imposed contexts. In contrast, smartmatch infers contexts from the actual types of its operands and uses that type information to select a suitable comparison mechanism.

And again:

The ~~ operator compares its operands “polymorphically”, determining how to compare them according to their actual types (numeric, string, array, hash, etc.).

Theoretically, ~~ cannot and will not coerce types — and yet, in the real world, in real code, it does. Perhaps this is another case for a ‘considered harmful’ article. In any case, here’s hoping for Perl 6, when everything will Just Work.