Search code examples
perlhashsmartmatch

Why does smartmatch against keys %h fail and give an "Argument isn't numeric" warning?


In the following code, why does the first smartmatch fail to match and give the warning Argument "two" isn't numeric in smart match, while the second smartmatch works as expected (it matches)?

use strict;
use warnings;
use feature 'say';

my %h = ("one" => "un", "two" => "deux");
my $v = "two";
my @keys_h = keys %h;

say "matches first form"  if $v ~~ keys %h; # warning, doesn't match
say "matches second form" if $v ~~ @keys_h; # no warning, matches

I realize I could just use

$v ~~ %h

but I'd like to know why the first smartmatch doesn't work as I expect it to. I'm using Perl 5.10.1.


Solution

  • Because an array and a list are not the same thing.

    $v ~~ @keys_h
    

    is matching a scalar against an array, (Any vs Array in the smart match behavior chart) returning true if the scalar matches an element of the array.

    $v ~~ keys %h
    

    is matching a scalar against a list. There is no rule for matching against a list, so the list is evaluated in scalar context, like

    $v ~~ scalar(keys %h)
    

    which resolves to

    "two" ~~ 2
    

    which is now a numeric comparison (Any vs. Num), which triggers the warning.

    $v ~~ [ keys %h ]
    

    would do what you want it to do, too.