Eugen Konkov Eugen Konkov - 2 months ago 11
Perl Question

How inheritance works when method is CODEREF?

In Mojo::EventEmitter we have next line of code:

for my $cb (@$s) { $self->$cb(@_) }


Where
$cb
is
CODEREF
of callback.

Will there any difference and which are if I write:

for my $cb (@$s) { $cb->($self, @_) }


I suppose that inheritance will not work because of
$cb
is
CODEREF
as it works in case when
$cb
contains string with a method name.
So in this case rewritten code will work similar.

Do I understand all right or miss something?

Answer

When $cb is a code reference, inheritance is not checked. In fact, $self is not examined at all.


When $cb is a code reference,

$self->$cb(@_)

is functionally identical to

$cb->($self, @_)

That's why $cb should be obtained using can, which follows inheritance.

package Parent {
   sub new { bless({ @_ }, shift) }
   sub method { CORE::say("!"); }
}

package Child {
   our @ISA = 'Parent';
}

my $self = Child->new();
my $method_name = 'method';

my $cb = $self->can($method_name)
   or die("The object's class doesn't have method $method_name\n");

$self->$cb();

Note that some people use

my $f = "function_name";
undef->$f();

as an alternative to

my $f = "sub_name";
no strict qw( refs );
$f->();

Yet, it's quite inappropriate to use a method call to call a non-method, and this trick only works if the sub has no parameters. If you really have a problem with this (appropriate) use of no strict, you can you the following trick:

my $f = "sub_name";
\&$f->();                # \&$f isn't subject to "use strict qw( refs );" checks