Reputation: 577
I use an external module (say Foo.pm) that I don't have control over. The way to use it is like below, which works fine:
use Foo ();
my %config = (
MODE => 'NORMAL',
ERROR => \&my_error, # error handling routine
);
Foo::init(%config);
sub my_error {
my ($message) = @_;
...
}
However I'm having trouble to pass in my_error()
to the external module when I'm writing in OO style as the first parameter to my_error()
is now $self
:
package MyPackage;
use Foo ();
sub new {
my $self = bless {
environment => 'TEST',
config => {
MODE => 'NORMAL',
ERROR => \&my_error, # WRONG ??!
},
}, __PACKAGE__;
Foo::init( %{$self->{config}} );
}
sub my_error {
my ($self, $message) = @_;
...
}
How do I solve it? Passing &{ $self->my_error }
does not seem to work.
Thanks!
Upvotes: 1
Views: 73
Reputation: 54323
A good alternative to the final part of ikegami's excellent and detailed answer is to use curry::weak.
use curry::weak;
my $self = bless({}, $class);
%$self = (
environment => 'TEST',
config => {
MODE => 'NORMAL',
ERROR => $self->curry::weak::my_error(),
},
);
mst, the author of curry, gives a reasonably understandble explanation of how that works in this lightning talk.
Upvotes: 4
Reputation: 385655
If you need a sub when you don't have one, you need to make one. You can make an anonymous one.
sub { $self->my_error(@_) }
So that means
my $self = bless {
environment => 'TEST',
config => {
MODE => 'NORMAL',
ERROR => sub { $self->my_error(@_) },
},
}, $class;
But there are complications. In your code, $self
hasn't been declared yet when you try to capture it. Fix:
my $self = bless({}, $class);
%$self = (
environment => 'TEST',
config => {
MODE => 'NORMAL',
ERROR => sub { $self->my_error(@_) },
},
);
But that creates a memory leak. The sub captures $self
, which references a hash that contains a reference to the sub. Fix:
use Scalar::Util qw( weaken );
my $self = bless({}, $class);
{
weaken( my $self = $self );
%$self = (
environment => 'TEST',
config => {
MODE => 'NORMAL',
ERROR => sub { $self->my_error(@_) },
},
);
}
As simbabque points out, the curry::weak module can simplify(?) this a little.
use curry::weak qw( );
my $self = bless({}, $class);
%$self = (
environment => 'TEST',
config => {
MODE => 'NORMAL',
ERROR => $self->curry::weak::my_error(),
},
);
But I think it'll just add confusion.
Upvotes: 7