Search code examples
maxminraku

perl6 min and max of mixed Str and Int arguments


What type gets converted first for min and max routine when the arguments contain mixture of Str and Int ?

To exit type 'exit' or '^D'
> say ("9", "10").max
9
> say ("9", "10").max.WHAT
(Str)
> say (9, "10").max
9
> say (9, "10").max.WHAT
(Int)                     # if convert to Int first, result should be 10
> say ("9", 10).max
9
> say ("9", 10).max.WHAT
(Str)                     # if convert to Str first, result should be 9
> say (9, "10").min
10
> say (9, "10").min.WHAT
(Str)                     # does min and max convert Str or Int differently?

If min or max converts arguments to be the type of the first argument, the results here are still inconsistent.


Solution

  • 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 both Ints then comparison is of two arbitrary precision integers).

    • If one argument is numeric but not the other, then -Inf and Inf are sorted to the start and end but otherwise comparison is done after both arguments are coerced by .Stringyfication.

    • Otherwise, both arguments are coerced by .Stringyfication.

    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. :)