Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can methods be treated as regular subroutines?

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.

like image 998
Luis F. Uceta Avatar asked Jul 15 '19 13:07

Luis F. Uceta


People also ask

Is a method a subroutine?

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.

Is method same as function and subroutine?

The terms "procedure, function, subroutine, subprogram, and method" all really mean the same thing: a callable sub-program within a larger program.

What are the 2 types of subroutine?

There are two types of subroutine: procedures. functions.

Are methods subprograms?

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.


2 Answers

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.

like image 133
Elizabeth Mattijsen Avatar answered Sep 22 '22 18:09

Elizabeth Mattijsen


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' }
}
like image 29
raiph Avatar answered Sep 18 '22 18:09

raiph