Method not found error when inheriting abstract method in Perl OOP - perl

I have a subclass that calls a method from a superclass. The method in the superclass uses a method that is defined in the superclass as abstract (not really abstract) but implemented in the subclass.
For example:
package BaseClass;
sub new
{
}
sub method1 {
return someAbstractMethod();
}
sub someAbtsractMethod
{
die "oops, this is an abstract method that should " .
"be implemented in a subclass" ;
}
1;
package SubClass;
sub new
{
}
sub someAbtsractMethod
{
print "now we implement the asbtract method";
}
1;
Now when I do:
$sub = new SubClass();
$sub->method1();
...it calls the abstract message and I get the specified error message. If I took off the abstract method from the super class and just leave the implementation in the subclass, It does not recognize the method and I get subroutine abstract method not found error.

You haven't set up an IS_A relationship between the parent and child classes.
You can do this with the base pragma as Ivan suggests, or you can manipulate the #ISA array. Or you can use the parent pragma.
#ISA:
package SubClass;
our #ISA = qw( BaseClass );
parent:
package SubClass;
use parent qw( BaseClass );
By the way, don't use the indirect object syntax ever. To call your constructor do:
my $foo = SubClass->new();
Also, it looks like you aren't using the strict and warnings pragmas. Do so. Always.
Finally, if you have multiple packages in one file, it is helpful to enclose each package in a block.
Check out perlboot and perltoot, they are handy OOP tutorials in the perldoc.
Update:
I just noticed that your method calls are broken. You need to find the invoking class or instance in each method.
package BaseClass;
sub new { bless {}, shift; } # horrible constructor - do not reuse.
sub abstract { die "The present situation is abstract"; }
sub method { my $self = shift; $self->abstract; }
package SubClass;
our #ISA = qw( BaseClass );
sub abstract { print "It's alive\n" );
In the script:
my $obj = SubClass->new;
$obj->method;
my $base = BaseClass->new;
$base->method;
Definitely read the tutorials I linked to. They will help you.

There are some problems with your code, you need to tell the subclass what its parent class is. You also probably need to setup your constructors to pass through to the parent class. There were also a few misspellings in there.
package BaseClass;
sub new {
bless {} => shift;
}
sub method1 {
my $self = shift;
return $self->someAbstractMethod();
}
sub someAbstractMethod
{
die "oops, this is an abstract method that should " .
"be implemented in a subclass";
}
package SubClass;
use base 'BaseClass';
sub new {
shift->SUPER::new
}
sub someAbstractMethod
{
print "now we implement the asbtract method\n";
}
package main;
my $obj = BaseClass->new;
eval {$obj->method1(); 1} or warn $#;
my $subobj = SubClass->new;
$subobj->method1();

Your fundamental problem is that you're not using method calls at all. Had you done
sub method1 {
my $self = shift;
$self->someAbstractMethod();
}
in the base class (and assuming inheritance was set up properly) then things would work. But when you write someAbstractMethod() that's not a method call, it's a function call, so it's resolved immediately at compile-time, without any regard for polymorphism (what the type of the object is).

If you are just starting out with Perl OO dont forget to check out Moose. See also Moose::Manual::Unsweetened for a comparison of Moose with regular Perl 5 OOP style.

Related

When and why would you use a class with no data members?

I have noticed some Perl modules use a class based structure, but don't manage any data. The class is simply used to access the methods within and nothing more.
Consider the following example:
Class.pm
package Class;
use Moose;
sub do_something {
print "Hi!\n";
}
1;
test.pl
use Class;
# Instantiate an object from the class
my $obj = Class->new();
$obj->do_something();
In this example you can see that you would first instantiate an instance of the class, then call the method from the created object.
The same end result can be achieved like so:
Module.pm
package Module;
use strict;
use warnings;
sub do_something {
print "Hi!\n";
}
1;
test.pl
use Module;
Module::do_something();
I am wondering why people write modules using the first approach, and if there is some benefit that it provides. To me it seems like it adds an extra step, because in order to use the methods, you first need to instantiate an object of the class.
I don't understand why people would program like this unless it has some benefit that I am not seeing.
One benefit is inheritance. You can subclass behavior of an existing class if it supports the -> style subroutine calls (which is a weaker statement than saying the class is object-oriented, as I said in a comment above).
package Class;
sub new { bless \__PACKAGE__,__PACKAGE__ }
sub do_something { "foo" }
sub do_something_else { 42 }
1;
package Subclass;
#Sublcass::ISA = qw(Class);
sub new { bless \__PACKAGE__,__PACKAGE__ }
sub do_something_else { 19 }
package main;
use feature 'say';
$o1 = Class->new;
$o2 = Subclass->new;
say $o1->do_something; # foo
say $o2->do_something; # foo
say $o1->do_something_else; # 42
say $o2->do_something_else; # 19
A prominent use of this technique is the UNIVERSAL class, that all blessed references implicitly subclass. The methods defined in the UNIVERSAL namespace generally take a package name as the first argument (or resolve a reference in the first argument to its package name), are return some package information. The DB class also does something like this (though the DB package also maintains plenty of state).

multi-level inheritance in Perl

I have a question related to multi-level inheritance in Perl.
Here is my code
mod.pm
package first;
sub disp {
print "INSIDE FIRST\n";
}
package second;
#ISA = qw(first);
sub disp {
print "INSIDE SECOND\n";
}
package third;
#ISA = qw(second);
sub new {
$class = shift;
$ref = {};
bless $ref, $class;
return $ref;
}
sub show {
$self = shift;
print "INSIDE THIRD\n";
}
1;
prog.pl
use mod;
$obj = third->new();
$obj->show();
$obj->disp();
I have a .pm file which contains three classes. I want to access the disp method in the first class using an object of third class. I'm not sure how that could work.
I tried to access using two ways:
using class name => first::disp()
using SUPER inside second package disp method => $self->SUPER::disp();
But am not sure how it will be accessed directly using the object of third class.
$obj->first::disp(), but what you are asking to do is something you absolutely shouldn't do. Fix your design.
If you need to do that, then you have defined your classes wrongly.
The third class inherits from the second class. second has it's own definition of disp, so it never tries to inherit that method from its superclass first. That means third gets the implementation defined in second
The simple answer would be to call first::disp something else. That way second won't have a definition of the method and inheritance will be invoked again
If you explain the underlying problem, and why you want to ignore an inherited method, then perhaps we can help you find a better way
Please also note that packages and module files should start with a capital letter, and each class is ordinarily in a file of its own, so you would usually use package First in First.pm etc.

Perl Moose augment vs around

Trying to understand Moose:
use Modern::Perl;
package FOO {
use Moose;
sub rep { say " <report></report>"; }
sub doc {
say "<document>";
inner();
say "</document>";
}
}
package BAR {
use Moose;
extends 'FOO';
around 'rep' => sub {
my $orig = shift;
my $self = shift;
say "<document>";
$self->$orig(#_);
say "</document>";
};
augment 'doc' => sub {
say " <report></report>";
};
}
package main {
BAR->new->rep;
say "===";
BAR->new->doc;
}
Produces...
<document>
<report></report>
</document>
===
<document>
<report></report>
</document>
... the same result. When desinging the "model (object hierarchy)" - based on what I should decide when to use around and when augment?
Here are probably other (deeper) things what i currently didn't understand yet.
Can please someone provide an "more deep" explanation, because reading tru the Moose/Manual/MethodModifiers obviously not helped enough...
augment and around do rather different things. augment is designed to make this sort of pattern easier:
package Document {
use Moose;
sub make_document {
my $self = shift;
return "<doc>" . $self->_document_innards . "</doc>"
}
# stub; override in child class
sub _document_innards {
my $self = shift;
return "";
}
}
package Invoice {
use Moose;
extends 'Document';
sub _document_innards {
my $self = shift;
return "Give me money!";
}
}
With augment it becomes:
package Document {
use Moose;
sub make_document {
my $self = shift;
return "<doc>" . inner() . "</doc>"
}
}
package Invoice {
use Moose;
extends 'Document';
augment make_document => sub {
my $self = shift;
return "Give me money!";
};
}
On the other hand, around is used as a replacement for doing $self->SUPER::method(#args) because SUPER can't work in roles (the notion of which package to check superclasses for is bound at compile-time, so $self->SUPER::method(#args) would check superclasses of the role (i.e. none) instead of superclasses of the class that consumed the role. If you're not using roles, then SUPER can still be used in Moose classes just fine. TLDR: SUPER is broken by roles, so Moose gives you around as an alternative.
Another thing to compare is override which is a bit like around, but gives you this super() function which is perhaps slightly cleaner than $self->$orig(#_). It also has an "there can be only one" feature. If two roles try to provide an around modifier for the same method, that's fine: they both get to wrap the method (though the order in which they are applied is undefined). If two roles try to provide an override modifier, that's an error.
The implementation of augment is somewhat fragile in my experience, so that in my book is a reason to avoid it. Don't try to replace it with around, because they do rather different things. Instead, replace it with the pattern used in my first example above.
Using around should always be your first instinct. As (Moose creator) Stevan Little says about augment:
Thankfully, only a small percentage of people actually grok this
feature and of those people only a handful of them are crazy enough to
try and use it.

How to handle this situation in object oriented perl

package a::b::c:d
my $res = a::b::c:e->new(); # i am doing like this
# is there any othere to do this
sub new {
...
my $self = {
#result = a::b::c:e->new();
}
}
sub test {
}
sub test2 {
}
1;
package a::b::c:e
sub new {
...
}
sub testresult {
}
1;
My question is:
how to initalize the e module in d in new itself rather creating every function and
how to use that to store some results into e:testresult
There are two strategies -- either examine the symbol table to initialize on creation, or make use of AUTOLOAD and test with can. AUTOLOAD can be messier as you have to deal with the case where the method isn't there:
sub AUTOLOAD {
my $self = shift;
my $method = $AUTOLOAD;
$method =~ s/.*://; # strip package name
if ( $self->{'result'}->can($method) ) {
return $self->{'result'}->$method(#_);
} else {
croak "Unknown method : $method";
}
}
But the symbol table trick is brittle, as if they're using inheritance, you won't see the inherited methods without walking up #ISA, too. (and even if they're not -- they might start using inheritance in the future, which results in things breaking)
...
Typically, when you're trying to copy another module's interface, you've got a case of inheritance, so you might want to ask yourself what the relationship is between ::d and ::e :
a::b::c::d is an a::b::c::e
a::b::c::d uses a::b::c::e
If it's an is-a relationship, it's typically better suited to inheritance (although you might have wrappers around each of the methods, and still need to go through this whole exercise anyway). If it's a uses relationship, odds are you don't want to inherit from every last method they have, and can just hard code a list (although, the list might change if the used class is updated)
foreach my $method ( #list_of_methods_to_copy ) {
*{$method} = sub {
my $self = shift;
return $self->{'results'}->$method(#_);
}
}
Provided that you're not looking for inheritance between the two classes, it looks to me that you might want to use Class::Delegator for composing your class. That way, you can create the delegation routines by putting the following in a::b::c::d.
use Class::Delegator send => 'testresult', to => '{result}';
But you'd need to fix your constructor anyway:
my $self
= bless {
result => a::b::c::e->new()
}, $class_name
;
return $self;
Having done that, you'd have a field '{result}' to delegate to.

Is there a point to Perl's object oriented interfaces if they're not creating objects?

I think I read somewhere that some modules only have object oriented interfaces ( though they didn't create objects, they only held utility functions ). Is there a point to that?
First, its important to remember that in Perl, classes are implemented in a weird way, via packages. Packages also serve for general namespace pollution prevention.
package Foo;
sub new {
my ($class) = #_;
my $self = bless {}, $class;
return $self;
}
1;
That is how you make a Foo class in Perl (which can have an objected instantiated by calling Foo->new or new Foo). The use of new is just a convention; it can be anything at all. In fact, that new is what C++ would call a static method call.
You can easily create packages that contain only static method calls, and I suspect this is what you're referring to. The advantage here is that you can still use OO features like inheritance:
package Bar;
sub DoSomething {
my ($class, $arg) = #_;
$class->Compute($arg);
}
sub Compute {
my ($class, $arg) = #_;
$arg * 2;
}
1;
package Baz;
#Baz::ISA = qw(Bar);
sub Compute {
my ($class, $arg) = #_;
$arg * 2 - 1
}
1;
Given that, then
say Bar->DoSomething(3) # 6
say Baz->DoSomething(3) # 5
In fact, you can even use variables for the class name, so these can function very much like singletons:
my $obj = "Baz"; # or Baz->new could just return "Baz"
print $obj->DoSomething(3) # 5
[Code is untested; typos may be present]
I suspect that this is mostly a philosophical choice on the part of authors who prefer OO to imperative programming. Others have mentioned establishing a namespace, but it's the package that does that, not the interface. OO is not required.
Personally, I see little value in creating classes that are never instantiated (i.e. when there's no object in object-oriented). Perl isn't Java; you don't have to write a class for everything. Some modules acknowledge this. For example: File::Spec has an OO interface but also provides a functional interface via File::Spec::Functions.
File::Spec also provides an example of where OO can be useful for uninstantiated "utility" interfaces. Essentially, File::Spec is an abstract base class -- an interface with no implementation. When you load File::Spec it checks which OS you're using and loads the appropriate implementation. As a programmer, you use the interface (e.g. File::Spec->catfile) without having to worry about which version of catfile (Unix, Windows, VMS, etc.) to actually call.
As others have said, inheritance is the big gain if an actual object is not needed. The only thing I have to add here is the advice to name your variables well when writing such interfaces, e.g.:
package Foo;
# just a static method call
sub func
{
my $class = shift;
my (#args) = #_;
# stuff...
}
I named the variable that holds the classname "$class", rather than $this, to make it clear to subsequent maintainers that func() will be called as Foo->func() rather than $foo->func() (with an instantiated Foo object). This helps avoid someone adding this line later to the method:
my $value = $this->{key};
...which will fail, as there is no object to deference to get the "key" key.
If a method might be called either statically or against an instantiated object (for example, when writing a custom AUTOLOAD method), you can write this:
my method
{
my $this = shift;
my $class = ref($this) || $this;
my (#args) = #_;
# stuff...
}
namespacing, mostly. Why not? Everything that improves perl has my full approval.