7stud has asked for the wisdom of the Perl Monks concerning the following question:

use strict; use warnings; use 5.010; my @numbers = (2); my @other = (2); if (@numbers ~~ @other) { say 'yes' }else{ say 'no'; } #output: yes if (@numbers ~~ (2)) { say 'yes' }else{ say 'no'; } #no

That problem came up when I tried to check whether an array was empty in a given-when:

given (@arr) { when (()) {say "The array is empty."} when (34) {say "The array contains 34."} default {say "Something else."} }

It seems kind of lame to have to do this:

given (@arr) { my @empty = () when (@empty) {say "The array is empty."} when (34) {say "The array contains 34."} default {say "Something else."} }

Can we send the smart operator back to school?

...and now I see I have problems with the second when too. This doesn't work at all for me:

my @arr1 = (2, 34); say "34" if @arr1 ~~ 34; #no output...??

This doesn't work either:

my @arr1 = ('hello', 'goodbye'); say "array size is 2" if @arr1 ~~ 2; #no output

Replies are listed 'Best First'.
Re: smart match operator should be smarter!
by ikegami (Patriarch) on Nov 21, 2009 at 18:34 UTC

    First of all, what's with all the useless parens?

    my @numbers = (2); => my @numbers = 2; my @other = (2); => my @other = 2; @numbers ~~ (2) => @numbers ~~ 2 my @empty = (); => my @empty;

    my @numbers = 2; @numbers ~~ 2 being false is to be expected. It was necessary to make ~~ non-commutative to fix bugs. In this case, since you're comparing against a simple scalar, a scalar comparison is made. You want 2 ~~ @numbers.


    As for when (()), it should give an error if it doesn't do anything useful. I'll see about reporting a bug. ( On second thought, empty list in scalar context returns undef. I don't think anything can be done about that. )


    Finally, keep in mind that when you specify an array, it's a reference to the array that's provided to the match operator.

    >perl -E"@a = qw(a b); say @a ~~ 2 ? 'match' : 'no match'" no match >perl -E"@a = qw(a b); say @a ~~ (0+\@a) ? 'match' : 'no match'" match

    The idea might be to allow the following

    >perl -E"@a = qw(a b); say \@a ~~ \@a ? 'match' : 'no match'" match

    but it actually uses a different rule.

    >perl -E"@a = qw(a b); @b = qw(a b); say \@a ~~ \@b ? 'match' : 'no ma +tch'" match

    This might be improvable. I'll see about bringing this up too.

      Can you explain what those examples are supposed to demonstrate?

      What I got out of it is that the naive rule is:

      1) the match operator compares references.

      Therefore, if you smart match @arr ~~ 2, you are doing this:

      my @arr = (10, 20, 30); my $aref = \@arr; say $aref; #ARRAY(0x1810e90) 0x1810e90 ~~ 2 --output:-- NOPE!

      However, the naive rule breaks down here:

      my @a = (10, 20, 30); my @b = (10, 20, 30); my $aref = \@a; my $bref = \@b; say $aref; say $bref; --output:-- ARRAY(0x1810e90) ARRAY(0x181ace0) #yet... say @a ~~ @b ? 'yes' : 'no'; --output:-- yes

      So you can't really say that the smart operator is comparing references, otherwise @a and @b would not match.

        Like I said, it's a different rule (ARRAY ~~ ARRAY instead of ANY ~~ NUM).

Re: smart match operator should be smarter!
by zwon (Abbot) on Nov 21, 2009 at 18:22 UTC

    You can use []

    use strict; use warnings; use 5.010; my @array = (); given(@array) { when([]) {say "array is empty"} default { say "there's something"} } my @numbers = (2); if (@numbers ~~ [2]) { say 'yes' }else{ say 'no'; }
Re: smart match operator should be smarter!
by JavaFan (Canon) on Nov 21, 2009 at 18:23 UTC
    my @a; give (@a) { when ([]) {say "yes"} }
    Prints "yes".
Re: smart match operator should be smarter!
by zwon (Abbot) on Nov 21, 2009 at 18:30 UTC
    This doesn't work at all for me:
    my @arr1 = (2, 34); say "34" if @arr1 ~~ 34; #no output...??

    This works for me. (it says "34")

    This doesn't work either:
    my @arr1 = ('hello', 'goodbye'); say "array size is 2" if @arr1 ~~ 2;

    This also works as documented (no output except warnings about comparing numeric value with strings)

      You must be using 5.10.0, where the implementation had many bugs.

        Yes, I'm using 5.10.0 (from Ubuntu 9.10, so it's not exactly 5.10.0), but I doesn't see any bugs. It looks like it works as it should work.

Re: smart match operator should be smarter!
by 7stud (Deacon) on Nov 21, 2009 at 18:37 UTC

    Ok, thanks. I see that my last problem is the same problem: you can't use the match operator with a literal. So you have to do this:

    my @arr1 = (2, 34); my $val = 34; say "34" if $val ~~ @arr1; #34

    But the smart match operator is supposed to be commutative, yet:

    my @arr1 = (2, 34); my $val = 34; say "34" if @arr1 ~~ $val; #no output...??

        Fixing the aforementioned bugs required making ~~ non-commutative.

        I don't see any aforementioned bugs???

        Ok, so not commutative anymore. Another flea from the llama 5th bit me.

Re: smart match operator should be smarter!
by Jorge_de_Burgos (Beadle) on Nov 22, 2009 at 20:09 UTC
    1. This is your untouched code and my results:
    use strict; use warnings; use 5.010; my @numbers = (2); my @other = (2); if (@numbers ~~ @other) { say 'yes' }else{ say 'no'; } #output: yes if (@numbers ~~ (2)) { say 'yes' }else{ say 'no'; } #output: yes

    2. This is my perl -v:

    This is perl, v5.10.0 built for i486-linux-gnu-thread-multi

    3. Could you post here the output of your perl -v?

      ikegami said earlier that the smart operator was changed after version 5.10.0. Apparently, it was buggy and too unwieldy to work with. As a result, it is no longer commutative.

      $ perl -v
      
      This is perl, v5.10.1 (*) built for darwin-2level
      
      Copyright 1987-2009, Larry Wall
      
      Perl may be copied only under the terms of either the Artistic License or the
      GNU General Public License, which may be found in the Perl 5 source kit.
      
      Complete documentation for Perl, including FAQ lists, should be found on
      this system using "man perl" or "perldoc perl".  If you have access to the
      Internet, point your browser at http://www.perl.org/, the Perl Home Page.