David W.
David W.

Reputation: 107080

Perl: Best way of making parent subroutine (not method) available to children

I have multiple classes defined in my main program. One is a parent class. The other are children classes:

# Main Program
...

package Foo;           #Parent class
....

sub glob2regex {
    my $glob = shift;
    ...here be dragons...
    return $regex;
};

....

package Foo::Bar;      #Child Class
base qw(Foo);

sub some_method {
   my $self = shift;
   my $regex = shift;
   my $type  = shift;

   if ( $type eq "glob" ) {
      $regex = glob2regex($regex);   #ERROR: glob2regex is not defined.
   }
   ...
}

I have a function in my parent class called glob2regex. It isn't really a method because it doesn't do anything with the object. Instead, it's a helper function that my child classes can use.

However, calling it in my child class as shown above won't work because it's not defined in my child class. I could prepend the full parent class name on it (i.e. call it as Foo::glob2regex instead of just glob2regex), or I could modify it into an object, and call it as $self->glob2regex. There maybe a even better way of handling this situation that I'm overlooking.

What is the best way to make a function like this that's defined in the parent class available in the child classes?

--

Test Program

#! /usr/bin/env perl
#
use strict;
use warnings;
use feature qw(say);
use utf8;

########################################################################
# MAIN PROGRAM 
my $bar = Foo::Bar->new;
$bar->just_foo_it;
#
########################################################################

########################################################################
#
package Foo;

sub lets_foo_it {
    say "I've done foo!";
}
#
########################################################################

########################################################################
#
package Foo::Bar;
use base qw(Foo);

*Foo::Bar::lets_foo_it = *Foo::lets_foo_it;

sub new {
    my $class = shift;
    my $self = {};
    bless $self, $class;
    return $self;
}

sub just_foo_it {
    my $self = shift;

    lets_foo_it();
}
#
########################################################################

Upvotes: 2

Views: 783

Answers (2)

ikegami
ikegami

Reputation: 386396

Exporting is usually done using Exporter.

BEGIN {
   package Foo;
   use Exporter qw( import );
   our @EXPORT_OK = qw( glob2regex );
   sub glob2regex { ... }
   ...
   $INC{'Foo.pm'} = 1;
}

BEGIN {
   package Foo::Bar;
   use Foo qw( glob2regex );
   our @ISA = 'Foo';
   ... glob2regex(...) ...
   $INC{'Foo/Bar.pm'} = 1;
}

Note that it's very unusual for a class module to export subroutines. You should consider it a red flag indicating a likely design flaw.

Upvotes: 4

Axeman
Axeman

Reputation: 29854

Seems like a bit of your problem is: "How do I use within a file?". I have a pragma I use in early development for this type of thing, but it breaks down to:

package Foo;
BEGIN { $INC{ __PACKAGE__ . '.pm'} = __FILE__ . ':' . ( __LINE__ - 1 ); }

Once it's in the %INC table, you're usually fine just using it.

Remember that a use is a require combined with an import at compile time. Once you've defined the Foo import, you can create an import function to take care of that part of use.

sub import { 
    my $caller = caller;
    return unless $caller->isa( __PACKAGE__ ); 
    {   no strict 'refs'; 
        *{"$caller\::glob2regex"} = *glob2regex{CODE};
    }
}

As I wrote above, I use this type of thing in early development--basically, when I want a sort of "scratchpad" with object relationships. In maintainable code, my preference would be to call Foo::glob2regex(...), or as I have at times insert it into a util package and export it from there:

package Foo::Util; 
use strict;
use warnings;
use parent 'Exporter';
our @EXPORT_OK = qw<glob2regex>;

sub glob2regex { ... }

Upvotes: 1

Related Questions