Can methods be treated as regular subroutines?

Have you considered passing names of methods around?

class Foo {
    method bar($a) { dd $a }
}
my $name = "bar";
Foo."$name"(42);  # 42

The syntax calls for the need of stringifications and parentheses to indicate you want to call that method. If you really want to use the Method object and pass that around, you can, but there is no real nice syntax for it:

class Foo {
    method bar($a) { dd $a }
}
constant &B = Foo.^find_method("bar");
B(Foo, 42)  # 42

In this example, the constant &B is created at compile time. But you can also call this method at runtime, e.g. when the name of the method is in a variable:

my $name = "bar";
my $method = Foo.^find_method($name);
$method(Foo, 42);

However, in that case, you would probably be better of with the ."$name"() syntax. See https://docs.raku.org/routine/find_method for a bit more info.


There are two general mechanisms for getting ahold of a method as a first class citizen (something that can be passed around as an argument), depending on whether a method is has scoped (almost all of them are) or my scoped.

.^find_method... to find a has scoped method

The vast majority of methods are held in classes and declared without an explicit scope declarator. These are all (implicitly) has scoped to the class containing them.

To pass a has scoped method around as an argument, you need to find it. The find operation must be initiated relative to some class that either contains that method or inherits from a class that contains it. This is true even if you know the method is in the very class from which you are initiating the find operation. There are three options:

  • .^find_method, as noted by ugexe++, is the usual tool. As you might expect, it searches inherited classes in Method Resolution Order, starting with the class of the .^find_method invocant.

  • On rare occasions you might want to use .^find_method_qualified instead. This starts the search higher up the MRO than the invocant's class.

  • There's one more method I'll include for completeness: .^lookup. But read the caveats in the doc. You almost certainly should NOT use this method, especially if what you wish to do is call the method. Use one of the .^find_method... methods instead.

So:

.has-way given class {
  method has-way { my $m = self.^find_method: 'm'; self.m-as-arg: $m }
  method m-as-arg ($m) { say self.$m } # has way
  method m { 'has way' }
}

&foo to refer to a my scoped method

A few methods are not has scoped but are instead declared with my.

For these lexical methods, the mechanism for passing them around as arguments is to simply refer to them with a prefix & sigil, just as you do for subs.

So:

.my-way given class {
  method my-way { self.m-as-arg: &m }
  method m-as-arg ($m) { say self.$m }     # my way
  my method m { 'my way' }
}