Smart Matching is Evil
Saturday, 27 April 2013; 11 pm
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
andkeys
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.
Related Posts
- The Art of Science Fiction 08 Oct 2013
- Space Cadet, Redux 03 Mar 2014
- The curious incident of elspeth in the mid-afternoon 08 Jun 2014
- The Beauty of Music 02 Dec 2012
- Mobile Phones: Assorted Thoughts 31 Jul 2013
About this post
- Date & Time
- 27 April 2013, 23:25:18
- Words
- 482
- Tags
- smartmatch and perl
- Extracted from
- Day One