Enheh
Enheh

Reputation: 227

In Perl 6, is there a way to get the Pod declarator block that is attached to a specific multi sub candidate?

Perl 6 has a cool feature which allows one to get any Pod declarator block that is attached to a subroutine (or class, role, etc.), using the WHY method:

#|(Some enlightening words about myfunc.)
sub myfunc (Int $i) { say "You provided an integer: $i"; };
#=(Some more words about myfunc.)

say &myfunc.WHY;

This displays:

Some enlightening words about myfunc.
Some more words about myfunc.

Unfortunately, when one has multiple candidates for a subroutine, one can't just invoke .WHY on the subroutine name:

#|(myfunc accepts an integer.)
multi myfunc (Int $i) { say "You provided an integer $i"; };
#|(myfunc accepts a string.)
multi myfunc (Str $s) { say "You provided a string $s"; };

say &myfunc.WHY;

The result:

No documentation available for type 'Sub'.
Perhaps it can be found at https://docs.perl6.org/type/Sub

Is there a way to get the Pod declarator block that is attached to a specific multi sub candidate? Is there a way to do so for all a subroutine's candidates?

Upvotes: 10

Views: 203

Answers (4)

mr_ron
mr_ron

Reputation: 479

You look up the multi with candidates or cando.

When initially posted I couldn't find a canned method for looking up a multi sub by signature but Christoph remedied that.

#| Initiate a specified spell normally
multi sub cast(Str $spell) {
  say "casting spell $spell";
}
#= (do not use for class 7 spells)

#| Cast a heavy rock etc in irritation
multi sub cast(Str $heavy-item, Int $n) {
  say "chucking $n heavy $heavy-item";
}

say "doc for cast spell";
say &cast.candidates[0].WHY;

say "doc for throwing rocks";
say &cast.candidates[1].WHY;

say "find doc for throwing things";
for &cast.candidates {
    if .signature ~~ :( Str, Int ) {
        say .WHY;
    }
}

# more advanced
say &cast.cando(\(Str, Int))>>.WHY; # thanks to Christoph
&cast.candidates.first: { .signature ~~ :(Str, Int) } andthen .WHY.say;

OUTPUT:

doc for cast spell
Initiate a specified spell normally
(do not use for class 7 spells)
doc for throwing rocks
Cast a heavy rock etc in irritation
find doc for throwing things
Cast a heavy rock etc in irritation
... repeated for variants ...

Upvotes: 8

Christoph
Christoph

Reputation: 169603

Get all documentation via candidates:

&myfunc.candidates>>.WHY

Get documentation of narrowest matching candidate via cando:

&myfunc.cando(\(42)).first.WHY

Upvotes: 7

Christopher Bottoms
Christopher Bottoms

Reputation: 11158

This is a little indirect, but ...

You can store each multi myfunc in a variable and call WHY on that variable, yet still call myfunc as before:

#!/bin/env perl6

#|(myfunc accepts an integer.)
my $func_int = multi myfunc (Int $i) { say "You provided an integer $i"; }
#=(More about Int version of myfunc)

#|(myfunc accepts a string.)
my $func_string = multi myfunc (Str $s) { say "You provided a string $s"; }
#=(More about Str version of myfunc)

myfunc(10);        # myfunc works as normal
say $func_int.WHY; # show POD declarator block

say ''; # Blank line to separate output into two groups

myfunc("bar"); 
say $func_string.WHY;

Resulting in this output:

You provided an integer 10
myfunc accepts an integer.
More about Int version of myfunc

You provided a string bar
myfunc accepts a string.
More about Str version of myfunc

This is using Rakudo Star 2018.01 on CentOS 6.7.

Upvotes: 4

jjmerelo
jjmerelo

Reputation: 23517

This does not really answer your question, but tries to explain why using WHY on a multi does not work; it's mainly because it points to the proto of the multi

#|(my-multi-func accepts either an integer or a string)
proto my-multi-func (|) {*}

#|(myfunc accepts an integer.)
multi my-multi-func (Int $i) { say "You provided an integer $i"; };
#|(myfunc accepts a string.)
multi my-multi-func (Str $s) { say "You provided a string $s"; };

say "my-multi-func is a {&my-multi-func.perl} and does {&my-multi-func.WHY}";

I attach the {&my-multi-func.perl} here because that is what gave me the hint. If you don't define a proto, it returns

my-multi-func is a sub my-multi-func (;; Mu | is raw) { #`(Sub|59650976) ... }

, which is none of the defined multis, ergo the proto. Of course if you want to access those particular definitions of the candidates, @Christopher Bottoms answer is just perfect.

Upvotes: 4

Related Questions