perl6 min and max of mixed Str and Int arguments
Both min
and max
use the cmp
infix operator to do the comparisons. If the types differ, then this logic is used (rewritten slightly to be pure Perl 6, whereas the real one uses an internals shortcut):
multi sub infix:<cmp>($a, $b) {
$a<> =:= $b<>
?? Same
!! a.Stringy cmp b.Stringy
}
Effectively, if the two things point to the exact same object, then they are the Same
, otherwise stringify both and then compare. Thus:
say 9 cmp 10; # uses the (Int, Int) candidate, giving Less
say "9" cmp "10"; # uses the (Str, Str) candidate, giving More
say 9 cmp "10"; # delegates to "9" cmp "10", giving More
say "9" cmp 10; # delegates to "9" cmp "10", giving More
The conversion to a string is done for the purpose of comparison (as an implementation detail of cmp
), and so has no impact upon the value that is returned by min
or max
, which will be that found in the input list.
Well, jnthn has answered. His answers are always authoritative and typically wonderfully clear and succinct too. This one is no exception. :) But I'd started so I'll finish and publish...
A search for "method min" in the Rakudo sources yields 4 matches of which the most generic is a match in core/Any-iterable-methods.pm6
.
It might look difficult to understand but nqp is actually essentially a simple subset of P6. The key thing is it uses cmp
to compare each value that is pulled from the sequence of values being compared against the latest minimum (the $pulled cmp $min
bit).
Next comes a search for "sub infix:<cmp>" in the Rakudo sources. This yields 14 matches.
These will all have to be looked at to confirm what the source code shows for comparing these various types of value. Note also that the logic is pairwise for each pair which is slightly weird to think about. So if there's three values a
, b
, and c
, each of a different type, then the logic will be that a
is the initial minimum, then there'll be a b cmp a
which will be whatever cmp
logic wins for that combination of types in that order, and then c cmp d
where d
is whichever won the b cmp a
comparison and the cmp
logic will be whatever is suitable to that pair of types in that order.
Let's start with the first one -- the match in core/Order.pm6
-- which is presumably a catchall if none of the other matches are more specific:
If both arguments of
cmp
are numeric, then comparison is a suitable numeric comparison (eg if they're bothInt
s then comparison is of two arbitrary precision integers).If one argument is numeric but not the other, then
-Inf
andInf
are sorted to the start and end but otherwise comparison is done after both arguments are coerced by.Stringy
fication.Otherwise, both arguments are coerced by
.Stringy
fication.
So, that's the default.
Next one would have to go thru the individual overloads. For example, the next one is the cmp
ops in core/allomorphs.pm6
and we see how for allomorphic types (IntStr
etc.) comparison is numeric first, then string if that doesn't settle it. Note the comment:
we define cmp ops for these allomorphic types as numeric first, then Str. If you want just one half of the cmp, you'll need to coerce the args
Anyhoo, I see jnthn's posted yet another great answer so it's time to wrap this one. :)