Search code examples
perlmojolicious

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?


Solution

  • 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 (documented) trick:

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