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)
).
You took a wrong turn in the middle. The important part is what nqp::existskey
is called with: the k.WHICH
. This method is there for value types, i.e. immutable types where the value - rather than identity - defines if two things are supposed to be the same thing (even if created twice). It returns a string representation of an object's value that is equal for two things that are supposed to be equal. For <1>.WHICH
you get IntStr|1
and for 1.WHICH
you get just Int|1
.
As explained in the Set documentation, sets compare object identity, same as the ===
operator:
Within a Set, every element is guaranteed to be unique (in the sense that no two elements would compare positively with the === operator)
The identity of an object is defined by the .WHICH method, as timotimo elaborates in his answer.
As you mention in your answer, your code works if you write your numbers as a simple comma separated list rather than using the <...>
construct.
Here's why:
4 ∈ set 1, 2, 3, 4 # True
A bare numeric literal in code like the 4
to the left of ∈
constructs a single value with a numeric type. (In this case the type is Int, an integer.) If a set
constructor receives a list of similar literals on the right then everything works out fine.
<1 2 3 4>
produces a list of "dual values"
The various <...>
"quote words" constructs turn the list of whitespace separated literal elements within the angle brackets into an output list of values.
The foundational variant (qw<...>
) outputs nothing but strings. Using it for your use case doesn't work:
4 ∈ set qw<1 2 3 4> # False
The 4
on the left constructs a single numeric value, type Int
. In the meantime the set
constructor receives a list of strings, type Str
: ('1','2','3','4')
. The ∈
operator doesn't find an Int
in the set because all the values are Str
s so returns False
.
Moving along, the huffmanized <...>
variant outputs Str
s unless an element is recognized as a number. If an element is recognized as a number then the output value is a "dual value". For example a 1
becomes an IntStr.
According to the doc "an IntStr can be used interchangeably where one might use a Str or an Int". But can it?
Your scenario is a case in point. While 1 ∈ set 1,2,3
and <1> ∈ set <1 2 3>
both work, 1 ∈ set <1 2 3>
and <1> ∈ set 1, 2, 3
both return False
.
So it seems the ∈
operator isn't living up to the quoted doc's claim of dual value interchangeability.
This may already be recognized as a bug in the ∈
set operation and/or other operations. Even if not, this sharp "dual value" edge of the <...>
list constructor may eventually be viewed as sufficiently painful that Perl 6 needs to change.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With