signaturerakumultidispatch

How does Perl 6's multi dispatch decide which routine to use?


Consider this program where I construct an Array in the argument list. Although there's a signature that accepts an Array, this calls the one that accepts a List:

foo( [ 1, 2, 3 ] );

multi foo ( Array @array ) { put "Called Array @ version" }
multi foo ( Array $array ) { put "Called Array \$ version" }
multi foo ( List $list )   { put "Called List version" }
multi foo ( Range $range ) { put "Called Range version" }

I get the output from an unexpected routine:

Called Array $ version

If I uncomment that other signature, that one is called:

Called List version

Why doesn't it call the ( Array @array ) version? How is the dispatcher making its decision (and where is it documented)?


Solution

  • I made a really dumb mistake, and that's why I wasn't seeing what I expected. You can't constrain a variable that starts with @. Any constraint applies to its elements. The Array @array denotes that I have a positional sort of thing in which each element is an Array. This is the same thing that raiph said. The odd thing is that the grammar looks the same but it does different things. It's something I've tripped over before.

    Since it's doing something different, it's not going to work out even if the data structure matches:

    foo( [ [1], [2], [3] ] );
    foo( [ 1, 2, 3 ] );
    
    multi foo ( Array @array ) { put "Called Array @ version" }
    multi foo ( Array $array ) { put "Called Array \$ version" }
    multi foo ( List $list )   { put "Called List version" }
    multi foo ( Range $range ) { put "Called Range version" }
    

    I still get the version I wouldn't expect based on the constraint and the data structure:

    Called Array $ version
    Called Array $ version
    

    I think this is just going to be one of Perl 6's warts that normal users will have to learn.