Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Raku's introspection list all the multi candidates across different files/Modules?

When a proto and multis are defined in the same module, Type.^lookup('method').candidates returns a list of all multi candidates. However, this appears not to work when the proto lives in a different file/module from the multis.

say Setty.^lookup('grab').candidates;   # OUTPUT: ()

Is there any way to find the full list of multi candidates through Raku's introspection? Or is there no alternative to grepping through the source code? (I ask because having a full list of multi candidates applicable to a given proto would be helpful for documentation purposes.)

like image 569
codesections Avatar asked Aug 20 '20 02:08

codesections


1 Answers

So far as multi methods go, it's not really to do with being in the same module or file at all. Consider these classes:

class Base {
    proto method m(|) { * }
    multi method m() { 1 }
}

class Derived is Base {
    multi method m() { 2 }
}

Whenever we compose a class that contains multi methods, we need to attach them to a controlling proto. In the case of Base, this was explicitly written, so there's nothing to do other than to add the multi candidate to its candidate list. Had we not written a proto explicitly in Base, however, then one with an empty candidate list would have been generated for us, with the same end result.

The process I just described is a bit of a simplification of what really happens, however. The steps are:

  1. See if this class has a proto already; if so, add the multi to it
  2. Otherwise, see if any base class has a proto; if so, clone it (in tern cloning the candidate list) and add the multi to that.
  3. Otherwise, generate a new proto.

And step 2 is really the answer to your question. If we do:

say "Base:";
.raku.say for Base.^lookup('m').candidates;

say "Derived:";
.raku.say for Derived.^lookup('m').candidates;

Then the output is:

Base:
multi method m (Base: *%_) { #`(Method|82762064) ... }
Derived:
multi method m (Base: ) { #`(Method|82762064) ... }
multi method m (Derived: ) { #`(Method|82762208) ... }

That is, the candidate list in Base has one entry, and the candidate list in Derived has the entry cloned from Base as well as a new one.

Pretty much everything follows this principle: derived classes reference their base class (and the roles they do), but base classes (and roles) don't know about their descendants.

like image 65
Jonathan Worthington Avatar answered Oct 26 '22 08:10

Jonathan Worthington