Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Can't locate object method- Issue

by perl_noobie (Initiate)
on Aug 02, 2013 at 06:40 UTC ( #1047553=perlquestion: print w/ replies, xml ) Need Help??
perl_noobie has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I'm new to OO perl and encountering the "Can't locate object method" issue. I have 2 classes with 2 subclasses under each of them - Person - Baby - Adult - Employee - IT - Finance I'm creating an obj for the Employee Subclass and based on the age of the employee, i'm loading a subclass from person. But i'm not able to call any method from the Person subclass. Posted my code below. Can someone please help? PS: Please note that each package is an individual file

package Person; use strict; use warnings; sub new { my $class = shift; my $self1 = { NAME => "erere", AGE => 233, @_, }; my $pkg; my $age = $self1->{AGE}; if ($age < 20) { $pkg = "Person::Baby"; } else { $pkg = "Person::Adult"; } eval "require $pkg"; my $function_name = $pkg . "::new"; my $func_ref = \&$function_name; my $self = $func_ref->($class, %$self1); return bless $self, $pkg; } sub sayHello { print "Hello from some Person\n"; } 1;
package Person::Adult; use strict; use warnings; use Exporter; use base ("Person"); use vars qw(@EXPORT @EXPORT_OK %EXPORT_TAGS); @EXPORT = qw( sayHi ); sub new { my $class = shift; my $self = { NAME => "erere", AGE => 233, @_, }; bless($self, "Adult"); return $self; } sub sayHi { my $self = shift; print "######## Adult says Hi !!!!!!!\n"; return; } 1; package Person::Baby; use strict; use warnings; use vars qw(@EXPORT @EXPORT_OK %EXPORT_TAGS); @EXPORT = qw( sayHi ); use base ("Person"); use Exporter; sub new { my $class = shift; my $self = { NAME => "erere", AGE => 233, @_, }; bless($self, "Baby"); return $self; } sub sayHi { my $self = shift; print "######## Baby says Hi !!!!!!!\n"; } 1; package Employee; use strict; use warnings; use base ("Person"); sub new { my $class = shift; my $self1 = { NAME => "nghnh", AGE => 23, @_, }; my $pkg; my $dept = $self1->{DEPT}; if ($dept =~ /IT/i) { $pkg = "Employee::IT"; } else { $pkg = "Employee::Finance"; } eval "require $pkg"; my $function_name = $pkg . "::new"; my $func_ref = \&$function_name; my $self = $func_ref->($class, %$self1); return bless $self, $pkg; } 1; package Employee::IT; use strict; use warnings; use base ("Employee", "Person"); sub new { my $class = shift; my $self = { NAME => "erere", DEPT => "IT", AGE => 23, @_, }; bless($self, "IT"); my $age = $self->{AGE}; if ($age < 20) { eval "require Person::Baby"; import Person::Baby; } else { eval "require Person::Adult"; import Person::Adult; } return $self; } 1; package Employee::Finance; use strict; use warnings; use base ("Employee", "Person"); sub new { my $class = shift; my $self = { NAME => "erere", DEPT => "Finance", AGE => 23, @_, }; bless($self, "Finance"); my $age = $self->{AGE}; if ($age < 20) { eval "require Person::Baby"; import Person::Baby; } else { eval "require Person::Adult"; import Person::Adult; } return $self; } 1;

below is my test code

use Employee; my $qq = Employee->new( NAME => "rtrtr", AGE => 54, DEPT => "IT", ); $qq->sayHello(); $qq->sayHi(); my $qw = Employee->new( NAME => "rtrtr", AGE => 25, DEPT => "FINANCE", ); $qw->sayHi();

I'm getting an error "Can't locate object method "sayHi" via package "Employee::IT""

Comment on Can't locate object method- Issue
Select or Download Code
Re: Can't locate object method- Issue
by Loops (Hermit) on Aug 02, 2013 at 06:56 UTC

    The Employee class is a subclass of Person which does not export a sayHi() method. If you make Employee a subclass of Person::Adult, the sayHi() method will be found. Alternatively you could just add a sayHi() method to Person.

      Employee is already a subclass of Person (by virtue of use base ("Person") in Employee module), and the actual subclass of Person( Adult or Baby) is imported via dynamic check condition. Can you pls point out in the code what changes is to be made?
        Importing (require) does not establish inheritance.
        لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

        You want to use

        use Exporter 'import';

        ... if you really want to export methods into other parts of base classes.

        Honestly, I do not think that mixing multiple inheritance, reblessing and exporting of subroutines in the way you are doing it will lead to a sane object/class structure. Maybe you can tell us more about the problem you are trying to solve with this conoction?

        On top of everything said by those more experienced monks above, you need to be careful when blessing an object that it actually matches one of your package names...
        bless($self, "Adult"); should be... bless($self, "Person::Adult");
        or even simple code that is not relying on your dynamic typing will fail:
        my $a = Person::Adult->new(NAME => 'the hard way'); $a->sayHi();
Re: Can't locate object method- Issue ($person->isBaby ->isAdult)
by Anonymous Monk on Aug 02, 2013 at 07:38 UTC
    FWIW, baby/adult should not be subclass, but one of these $person->isBaby, $person->isAdult
Re: Can't locate object method- Issue
by tobyink (Abbot) on Aug 02, 2013 at 08:42 UTC

    This is wrong in just so many ways.

    1. Firstly, just scrap all the import/export stuff. It will not do what you want it to do. Exporting and object-oriented programming have nothing to with each other.

      There are many people who claim that you ought never do both of them in the same package. I personally wouldn't go that far, but in your example there's really no need for any exporting, and I'd suggest that you lay off trying to combine exporting and OO until you're more comfortable with OO concepts.

    2. Secondly, a related issue: this eval "require Person::Baby"; import Person::Baby; stuff ain't gonna work. You appear to be wanting to set up something like per-object inheritance. Not gonna happen. Inheritance in Perl happens on a per-class basis; not per-object. However, you may be able to accomplish what you want using run-time application of roles to objects. (See Role::Tiny, Moo::Role, Moose::Role, etc.)

    3. Thirdly, you're blessing most of your objects incorrectly. As an example, you have a package called "Person::Adult", but then bless objects into a package called just "Adult".

    4. I don't know how to continue. But there is plenty of other weird stuff you're doing. Please find a tutorial on OO Perl. You won't find any mention of all this import/export stuff. Pick up a copy of chromatic's book Modern Perl; IIRC is has some good stuff on OO programming. The Kindle edition costs but a few beans; the printed edition slightly more; but chromatic makes the HTML and PDF versions available online for free, so you can't say fairer than that, can you?

    Anyway, here's how I'd do it using Moo and Moo::Role...

    Lastly, 19 year olds generally don't appreciate being referred to as babies.

    Update: if you wanted to split the packages out into separate files, then you'd need to make sure they're all loaded...

    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
      Thanks for the implementation idea. Though the sample script that you have given works well if maintained in a single file, I tried splitting each package in a new file and this does not work as expected. Can someone help resolve this?

        See my recent update.

        package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1047553]
Approved by Happy-the-monk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (7)
As of 2014-09-03 06:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite cookbook is:










    Results (35 votes), past polls