gzartman has asked for the wisdom of the Perl Monks concerning the following question:

I'm somewhat new to perl OOP. I've been working on a perl module and found that it was getting a big unwieldy, so decided to spin off a few child classes to my main class to help organization and what not. I'd like to be able to call methods from the child class as if they were in the parent class (at least that's how I envisioned this working). Simplified example:
package parentClass; use parentClass::childClass; sub new { my ($class, %params) = @_; my $self = {}; bless ($self, $class); return ($self); } 1; package parentClass::childClass; sub new { my ($class, %params) = @_; my $self = {}; bless ($self, $class); return ($self); } sub myMethod { return ('Yo I am one sweet method'); } Test Script utilizing these classes: use parentClass; $object = parentClass->new(); print $object->myMethod();
When I do this, perl complains that it can't find myMethod. I'm betting this is something fairly simple, but I can' figure it out. Thanks.

Replies are listed 'Best First'.
Re: Method of child module called by parent
by Athanasius (Archbishop) on Dec 26, 2014 at 07:09 UTC

    Hello gzartman, and welcome to the Monastery!

    I'd like to be able to call methods from the child class as if they were in the parent class

    You have that back-to-front! Child classes inherit from their parents; parent classes ought to have no knowledge of their children. So when you have code like this:

    package parentClass; use parentClass::childClass;

    it’s almost always a symptom of a faulty OO design.

    I've been working on a perl module and found that it was getting a big unwieldy, so decided to spin off a few child classes to my main class to help organization and what not.

    A child class specialises its parent in a way that makes for an asymmetrical ISA relationship. For example, owl specialises bird, because an owl ISA bird (but a bird is not necessarily an owl). So, anything a bird can do, an owl can do too (but most likely in a distinctively owlish way). And an owl can do things other birds can’t: for example, $owl->hunt_at_night() or $owl->hoot() make a lot more sense than $sparrow->hunt_at_night() or $sparrow->hoot(). So it makes little sense to give hunt_at_night or hoot methods to package bird; and still less sense to try to allow a bird (which could be an eagle, a toucan, or a dodo) to hoot in the way owls do!

    I suspect what you’re looking for is a helper class which your parent class accesses via a HASA or USES relationship. But in the absence of concrete details it’s hard to give more definite advice.

    By the way:

    1. Please put your code in <code> ... </code> tags; see Markup in the Monastery.

    2. The standard convention is to begin a package name with an uppercase letter: ParentClass, ParentClass::ChildClass;.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      I suspect what you’re looking for is a helper class which your parent class accesses via a HASA or USES relationship. But in the absence of concrete details it’s hard to give more definite advice.

      Yes, that is essentially what I'm trying to do.

      Specifically, I'm working on an API for Samba 4 Active Directory using Net::LDAP. The API is meant to abstract much of the LDAP code needed to query the AD. For example, you could ask the api:

      @posix_users = $ad->listObjects('users','posix');

      And then the API would spit out the requested data. The problem I was running into is that the over all perl module was getting large in size, so I thought I'd try and spin off some of the methods to sub-classes. Good examples are those methods associated with users would get a module: Users.pm. And then those associated with groups, Groups.pm.

      So my module structure looks like this:

      esmith::AD (AD.pm)
      - esmith::AD::Users (Users.pm)
      - esmith::AD::Groups (Groups.pm)

      The methods in Users.pm and Groups.pm really do specialize active directory objects generated in the parent module. Following your example, a user ISA object.

      So the primary reason for wanting the parent class to see the child class methods, we me being lazy, I think.

      Lazy Code (child method called from parent constructor): use esmith::AD; use strict; my $ad=esmith::AD->new(); warn "User exists\n" if ($ad->doesUserExist('greg')); Proper code (child method called from child constructor): use esmith::AD::User; use strict; my $ad=esmith::AD::User->new(); warn "User exists\n" if ($ad->doesUserExist('greg'));

      Is this more along the lines that you were trying to explain?

        Hello gzartman,

        Thanks for adding the <code> tags to the OP.

        If you really need do need to call doesUserExist() from the parent class (which I doubt), you’ll have to give the parent class a default version of this method, then override it in the child class(es) as needed. For example (untested):

        package esmith::AD; sub doesUserExist { return 0; # default answer: 'No' } package esmith::AD::User; use List::Util qw( any ); my @user_names; # class variable sub doesUserExist { my ($self) = @_; # assuming that $self is a hash reference return any { $_ eq $self->{Name} } @user_names; }

        But I still don’t see what you gain by this. In your example, the “lazy” code is no shorter than the “proper” code, so why not just use the latter?

        It occurs to me that you might, just possibly, be looking for some form of factory, but again this seems like overkill unless you have a good reason for it?

        Update: The test for whether or not a new user already exists should, of course, be done in the constructor.

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        Some food for thought

        my $ad = AD->new( $server, $login, $pass ); if( my $user = $ad->GetUser( 'craig' ) ){ $user->replace( company => 'rompany' ); $user->company( 'rompany' ); } else { $ad->AddUser( company => 'rompany', ); } sub AD::new { ... return $conn } sub AD::GetUser { my( $conn, $user ) = @_; return AD::User->get( conn => $conn, user => $user ); } sub AD::AddUser { my $conn = shift; Add::User->add( conn => $conn, @_ ); } sub AD::GetGroup { my( $conn, $group ) = @_; return AD::Group->get( conn => $conn, user => $group ); } sub AD::User::add { ... croak "name cannot be 42"; }

        More food for thought App::LDAP, Net::LDAP::Class, Catalyst::Model::LDAP

Re: Method of child module called by parent
by locked_user sundialsvc4 (Abbot) on Dec 28, 2014 at 18:08 UTC

    Yes, you definitely have “the OOP idea” upside-down and backwards.   :-)   When you “call a method for an object,” you should not have to care exactly which method(s) ultimately get called.   Perl will search for the method, at runtime, by walking-up the inheritance chain from child to parent, invoking (only) the first method that it finds.   If a method in a child-class “overrides” an identically-named method in the parent, the parent method will never be directly called by Perl, but the child method can do so by means of ::SUPER, which will cause Perl to search again for another method to call, starting its search with the superclass (use base) of the child.   (Therefore, theoretically, the child does not have to be concerned as to exactly which “method of a superclass” Perl will find, simply relying upon Perl to find it at runtime.)

    Modules which implement descendent classes will use the modules which define their immediate parent.   It should (almost) never be necessary for a parent-module to use any modules which define descendent classes.   If you find yourself doing that, “something’s wrong.”   (Common-code that needs to be shared by several modules, regardless of their class relationship, should probably be spun-off into a third module, for instance.)

    One thing that sometimes catches people off-guard about Perl is the extent to which it relies upon at-runtime resolution of things, and how little it relies upon (or provides ...) compile-time specification of things.   Many programming languages are designed such that “incorrect” method-calls can be detected at compile time, through the use of strong-typing and so forth.   Perl simply does not have these things.   This gives it a tremendous amount of flexibility, but it does change the nature of compile-time declarations (e.g. use) in a way that you might initially find to be surprising.   You can specify any variable, and any method-name, in a $varname->methodname construct, and no compile-time error or warning will be generated.   You might be accustomed to different language behavior.