Search code examples
setrakumoarvm

How do the Perl 6 set operations compare elements?


Running under moar (2016.10)

Consider this code that constructs a set and tests for membership:

my $num_set = set( < 1 2 3 4 > );
say "set: ", $num_set.perl;
say "4 is in set: ", 4 ∈ $num_set;
say "IntStr 4 is in set: ", IntStr.new(4, "Four") ∈ $num_set;
say "IntStr(4,...) is 4: ", IntStr.new(4, "Four") == 4;
say "5 is in set: ", 5 ∈ $num_set;

A straight 4 is not in the set, but the IntStr version is:

set: set(IntStr.new(4, "4"),IntStr.new(1, "1"),IntStr.new(2, "2"),IntStr.new(3, "3"))
4 is in set: False
IntStr 4 is in set: True
IntStr(4,...) is 4: True
5 is in set: False

I think most people aren't going to expect this, but the docs doesn't say anything about how this might work. I don't have this problem if I don't use the quote words (i.e. set( 1, 2, 3, 4)).


Solution

  • I think this is a bug, but not in the set stuff. The other answers were very helpful in sorting out what was important and what wasn't.

    I used the angle-brackets form of the quote words. The quote words form is supposed to be equivalent to the quoting version (that is, True under eqv). Here's the doc example:

    <a b c> eqv ('a', 'b', 'c')
    

    But, when I try this with a word that is all digits, this is broken:

     $ perl6
     > < a b 137 > eqv ( 'a', 'b', '137' )
     False
    

    But, the other forms work:

    > qw/ a b 137 / eqv ( 'a', 'b', '137' )
    True
    > Q:w/ a b 137 / eqv ( 'a', 'b', '137' )
    True
    

    The angle-bracket word quoting uses IntStr:

    > my @n = < a b 137 >
    [a b 137]
    > @n.perl
    ["a", "b", IntStr.new(137, "137")]
    

    Without the word quoting, the digits word comes out as [Str]:

    > ( 'a', 'b', '137' ).perl
    ("a", "b", "137")
    > ( 'a', 'b', '137' )[*-1].perl
    "137"
    > ( 'a', 'b', '137' )[*-1].WHAT
    (Str)
    > my @n = ( 'a', 'b', '137' );
    [a b 137]
    > @n[*-1].WHAT
    (Str)
    

    You typically see these sorts of errors when there are two code paths to get to a final result instead of shared code that converges to one path very early. That's what I would look for if I wanted to track this down (but, I need to work on the book!)

    This does highlight, though, that you have to be very careful about sets. Even if this bug was fixed, there are other, non-buggy ways that eqv can fail. I would have still failed because 4 as Int is not "4" as Str. I think this level of attention to data types in unperly in it's DWIMery. It's certainly something I'd have to explain very carefully in a classroom and still watch everyone mess up on it.

    For what it's worth, I think the results of gist tend to be misleading in their oversimplification, and sometimes the results of perl aren't rich enough (e.g. hiding Str which forces me to .WHAT). The more I use those, the less useful I find them.

    But, knowing that I messed up before I even started would have saved me from that code spelunking that ended up meaning nothing!