Search code examples
perloopimportradix

Perl call import from base class


I have a base class called A:

package A;
use strict;
use warnings;
use v5.12;

sub import {
    my $caller = caller;
say 'import called from ' . $caller;
    if (not $caller->can('has')) {
        no strict 'refs';
say "--> import has to $caller";
        *{"${caller}::has"} = sub { _attr($caller, @_) };
    }
}

sub _attr {
    my ($class, $name, $default) = @_;
    no strict 'refs';
    *{"${class}::$name"} = sub {
        my ($self, $value) = @_;
        $self->{$name} = $value if $value;
        return $self->{$name} // $default;
    };
}

1;

And have a child class B:

package B;
use strict;
use warnings;
use lib './';
use base 'A';
use v5.12;

#use C;
A->import();

has 'ans' => 42;
say ans();

1;

If I'm trying to run this code, I've got an syntax error but if I make these changes has 'ans' => 42' to has('ans' => 42); then all works great.

Or if I've create class C:

package C;
use strict;
use warnings;
use lib '.';
use base 'A';

1;

then I do not need to modify this code has 'ans'... to has(... because all is works.

So, I've can't understand why this happens. How I can import subroutine has in a child modules?


Solution

  • To import has from A into any other module you simply need to put use A into that module.

    Replace this line:

    A->import();
    

    with:

    use A;
    

    and it will do what you want.

    Manually calling ->import doesn't do what you want because it happens at run time, and the import needs to happen at compile time in order for perl to know that has is a subroutine name before it parses the line that uses it. use is a compile-time command, so has effect before the has line gets parsed.