Reputation: 54074
How can I pass a reference to a module's function as parameter in a function call of another module?
I tried the following (simple example):
This is the module that has a function (process_staff) that takes as a parameter a function reference (is_ok).
#!/usr/bin/perl
use strict;
use warnings;
package Objs::Processing;
sub new {
my ($class) = @_;
bless {} ;
}
sub process_staff {
my ($employee, $func) = @_;
if($func->is_ok($employee)) {
print "Is ok to process\n";
}
else {
print "Not ok to process\n";
}
}
1;
This is the module that implements the passed function (is_ok)
#!usr/bin/perl
use strict;
use warnings;
package Objs::Employee;
my $started;
sub new {
my ($class) = @_;
my $cur_time = localtime;
my $self = {
started => $cur_time,
};
print "Time: $cur_time \n";
bless $self;
}
sub get_started {
my ($class) = @_;
return $class->{started};
}
sub set_started {
my ($class, $value) = @_;
$class->{started} = $value;
}
sub is_ok {
my ($emp) = @_;
print "In is ok I received:\n";
use Data::Dumper;
print Dumper($emp);
return 1;
}
This is my test script that I run:
#!/usr/bin/perl
use strict;
use warnings;
use Objs::Manager;
use Objs::Processing;
my $emp = Objs::Manager->new('John Smith');
use Data::Dumper;
print Dumper($emp);
my $processor = Objs::Processing->new();
$processor->process_staff(\&$emp->is_ok); #error is here
I get a:
Not a CODE reference at testScript.pl line 14.
I also tried: $processor->process_staff(\&$emp->is_ok());
but also still does not work.
What am I doing wrong here
Upvotes: 5
Views: 1323
Reputation: 385657
It's not specifically what you asked for, but I think you simply need the following:
sub process_staff {
my ($self, $emp) = @_;
if ($emp->is_ok()) {
print "Is ok to process\n";
}
else {
print "Not ok to process\n";
}
}
$processor->process_staff($emp);
Upvotes: 1
Reputation: 50637
You can pass anonymous coderef which returns result from desired method,
$processor->process_staff(sub{ $emp->is_ok(@_) });
@_
can be dropped as is_ok
method doesn't take any arguments.
Upvotes: 2
Reputation: 98388
You appear to want to pass an object and a method to call on it; the easiest way to do that would be:
$processor->process_staff( sub { $emp->is_ok } );
where process_staff looks like:
sub process_staff {
my ($self, $func) = @_;
if ( $func->() ) {
...
or you can pass the reference and the object separately:
sub process_staff {
my ($self, $emp, $method) = @_;
if ( $emp->$method() ) {
...
$processor->process_staff( $emp, $emp->can('is_ok') );
Upvotes: 5
Reputation: 66957
In this expression:
$processor->process_staff(\&$emp->is_ok);
You are saying "call the method $emp->is_ok
, take the return value, treat it as a CODE
reference, dereference it, and return a reference to that. That doesn't work, since the return value from that sub is not a CODE
reference.
To do what you want, you can use a reference to an anonymous sub to wrap the call to your object method:
$processor->process_staff( sub { $emp->is_ok } );
Upvotes: 2
Reputation: 27207
I think this could work with:
$processor->process_staff(\&Objs::Employee::is_ok);
where you pass in the method ref.
and where you currently have
if( $func->is_ok($employee) ) {
you need
if( $func->( $employee ) ) {
This is because you cannot reference named methods simply from an object, by the syntax \&$obj->method
.
However, in your example code it is not at all clear why you don't do this instead:
if( $employee->is_ok() ) {
in which case you would not need to reference the method to call in process_staff
at all. There are also other ways to achieve the same method indirection that might give you better encapsulation in future.
Upvotes: 1