Is it possible to assign methods to variables and pass them around as arguments inside the class similar to subroutines?
I know they're are accessible by either self.
or self!
(or whatever named explicit invocant) inside other methods but I'm wondering if it's possible to pass a method's code object as an argument to another method.
A subroutine that is in a class or object is often called a method, and "method" is the term that most people prefer for subroutines in Java.
The terms "procedure, function, subroutine, subprogram, and method" all really mean the same thing: a callable sub-program within a larger program.
There are two types of subroutine: procedures. functions.
A method is a set of code which is referred to by name and can be called (invoked) at any point in a program simply by utilizing the method's name. Think of a method as a subprogram that acts on data and may, or may not, return a value.
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 methodThe 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 methodA 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 sub
s.
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' }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With