methodsrakucurryingcallable

How do you create a callable variable to call a class method with arguments?


I'm trying to create a callable variable for a class method.

class Person {
    method walk(Str $direction) {
        say "Walking $direction";
    }
}

I can create a callable variable for the method 'walk' that works as expected.

my $person = Person.new;
my $callable = $person.^find_method('walk');
$person.$callable('up'); # OUTPUT: "Walking up"

Now I want to create a callable that will call method 'walk' with the parameter 'up'.

my $callable = $person.^find_method('walk').assuming('up');
$person.$callable(); 

    # Type check failed in binding to parameter '$direction'; expected Str but got Person (Person.new)
    #   in sub __PRIMED_ANON at EVAL_7 line 1
    #   in block <unit> at <unknown file> line 1

$person.$callable (without the parentheses) gives the same error

I tried calling it 'directly', but got a different error.

$person.^find_method('walk')('up')
    # Too few positionals passed; expected 2 arguments but got 1
    #   in method walk at <unknown file> line 2
    #   in block <unit> at <unknown file> line 1

Is this possible?


Solution

  • Yes, this is possible. The missing piece is that methods implicitly receive their invocant as their first positional parameter (that is, the signature of Person's walk method is really method walk(Person: Str $direction)) and receive self as their first positional argument.

    This means that you need to use assuming to supply the second positional argument instead of the first. Here's how that'd look:

    class Person {
        method walk(Str $direction) {
            say "Walking $direction";
        }
    }
    my $person = Person.new;
    my $callable = $person.^find_method('walk').assuming(*, 'up');
    $person.$callable();  # # OUTPUT: "Walking up"
    

    As another option, instead of using * for the first positional parameter, you could use $person; if you did that, $callable() would return "Walking up" without needing to be invoked on a Person.