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?
1 Answer
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
.