Overriding a class method with an object method

  • Thread starter Koszalek Opalek
  • Start date
K

Koszalek Opalek

Hello,

A method in the base class can be overridden in the derived class.
My question is: can an _object_ override a method in its base class?
Here is a simple class P with two methods: new() and meth(). I would
like to create an object of class P that uses its own method meth().

#!/usr/bin/perl
use strict;
use warnings;
{
package P;

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

};

sub meth
{
my $self = shift;
print "This is a class method.\n";

};
};

my $obj = P->new(
meth => sub { print "This is an object method.\n" }
);

$obj->meth;

The code above will (obviously) print
This is a class method.
I would like it to call the sub defined in the object $obj and print
This is an object method.

I came up with the following solution (this is a new implementation
of method meth() in the class P):

sub meth
{
my $self = shift;
if ($self->{meth}) {
&{$self->{meth}};
} else {
print "This is a class method.\n";
};

};

Is there a more elegant way?

K.
 
A

anno4000

Koszalek Opalek said:
Hello,

A method in the base class can be overridden in the derived class.
My question is: can an _object_ override a method in its base class?
Here is a simple class P with two methods: new() and meth(). I would
like to create an object of class P that uses its own method meth().

#!/usr/bin/perl
use strict;
use warnings;
{
package P;

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

};

sub meth
{
my $self = shift;
print "This is a class method.\n";

};
};

my $obj = P->new(
meth => sub { print "This is an object method.\n" }
);

$obj->meth;

The code above will (obviously) print
This is a class method.
I would like it to call the sub defined in the object $obj and print
This is an object method.

I came up with the following solution (this is a new implementation
of method meth() in the class P):

sub meth
{
my $self = shift;
if ($self->{meth}) {
&{$self->{meth}};
} else {
print "This is a class method.\n";
};

};

So you want a method that behaves one way when called as an object
method and another way if called as a class method?

You need a check that finds out what the invocant is (class or method)
without failing in one of the cases. That is the problem with your
approach -- it dies when called as a class method. Instead, check
whether the invocant is a reference. If it is, assume an object,
otherwise the class name. Untested:

sub meth {
my $whatever = shift;
if ( ref $whatever ) {
# got an object
$whatever->{ meth}->();
} else {
# class method call
print "This is an object method.\n";
}
}

Anno
 
E

eminencja

So you want a method that behaves one way when called as an object
method and another way if called as a class method?

No, I want to create object Obj based on class P that overrides
a method defined in the class.

Assume the class has a method blahBlah() that prints "blah blah".
Objects based on this class can use that method, i.e. saying
$obj2->blahBlah
will print
"blah blah."

I would like to create an object that overrides this class method
so that when I say
$Obj->blahBlah
the object will print
"I'm special"

The solution I sent in (see my previous post) does work but
I hope there is an easier way(?).

K.
 
A

anno4000

No, I want to create object Obj based on class P that overrides
a method defined in the class.

Your terminology is off. Objects don't override methods, methods
(in a client class) override methods (in a base class). Your use
of "class method" and "object method" is also off kilter. This
makes it hard to understand what you really want to do.

What you have *written* is simply a method that looks at a certain
field in the object and shows different behavior depending on what
it finds. (It claims to be a class method in one case, which isn't
the case.) No overriding is involved.

Whether it is essential to your solution that the object contains
(part of) the method code is unfortunately not clear. I'll assume
its a coincidental part of your specific solution. You could have
gotten the same effect by simply saying (untested):

sub meth {
my $obj =shift;
if ( $obj->{ i_am_special } ) {
print "Special behavior\n";
} else {
print "Normal behavior\n";
}
}

....plus a corresponding change in object construction

my $obj = P->new( i_am_special => 1);

Overriding is still not involved, it's just a method.
Assume the class has a method blahBlah() that prints "blah blah".
Objects based on this class can use that method, i.e. saying
$obj2->blahBlah
will print
"blah blah."

I would like to create an object that overrides this class method
so that when I say
$Obj->blahBlah
the object will print
"I'm special"

That doesn't make sense.
The solution I sent in (see my previous post) does work but
I hope there is an easier way(?).

That solution doesn't override anything.

Here is a setup that *does* use method overriding to achieve something
similar:


package P;

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

sub meth { print "This is one behavior.\n" }

package Q;
use base 'P';

sub meth { print "This is another behavior.\n" }


package main;

my $obj = P->new();
my $other = Q->new();
$obj->meth;
$other->meth();
__END__

Anno
 
M

Martijn Lievaart

Your terminology is off. Objects don't override methods, methods (in a
client class) override methods (in a base class). Your use of "class
method" and "object method" is also off kilter. This makes it hard to
understand what you really want to do.

The terminology is off in Perlish, but it makes perfect sense in a
greater context.

What you can do is define a subclass with the other method, then rebless
the object into this new class. I'm not sure this would work, but I think
it does.

Starting from there, one can use subroutine references or tricks with
eval to make it even more generic.

HTH,
M4
 
C

Ch Lamprecht

Koszalek said:
Hello,

A method in the base class can be overridden in the derived class.
My question is: can an _object_ override a method in its base class? No

I came up with the following solution (this is a new implementation
of method meth() in the class P):

sub meth
{
my $self = shift;
if ($self->{meth}) {
&{$self->{meth}};
} else {
print "This is a class method.\n";
};

};

Is there a more elegant way?

Here is an example with an attribute that holds a coderef.
It's a matter of taste, but I think 'use Moose' makes it more elegant ;)

use warnings;
use strict;
package MyClass;
use Moose;

has behaviour => (isa => 'CodeRef',
is => 'rw',
default => sub {sub{print "my standard behaviour\n"}},
);

sub show_behaviour{
my $self = shift;
$self->behaviour->();
}

package main;

my $inst = MyClass->new;
$inst->show_behaviour;

$inst->behaviour(sub{print "my special behaviour\n"});
$inst->show_behaviour;
 
A

anno4000

Martijn Lievaart said:
The terminology is off in Perlish, but it makes perfect sense in a
greater context.

How can it? An apple can't override an orange, an object can't override
a method. It's a conceptual mismatch.
What you can do is define a subclass with the other method, then rebless
the object into this new class. I'm not sure this would work, but I think
it does.

If you re-bless the object the subclass relation becomes irrelevant.
(Btw, few OO languages support re-blessing the way Perl does.)

What you can do is create a base class that defines the "normal"
behavior, and a subclass that overrides the normal behavior with
a special one. I've given an example of that upthread. But then
it's a *method* in the subclass that overrides the base method.
Starting from there, one can use subroutine references or tricks with
eval to make it even more generic.

I don't know what that means.

Anno
 
M

Martijn Lievaart

How can it? An apple can't override an orange, an object can't override
a method. It's a conceptual mismatch.

A class is a blueprint for the object, so it makes perfect sense to let
an object override the default provided by the class.
If you re-bless the object the subclass relation becomes irrelevant.
(Btw, few OO languages support re-blessing the way Perl does.)

What you can do is create a base class that defines the "normal"
behavior, and a subclass that overrides the normal behavior with a

That's what I meant.
special one. I've given an example of that upthread. But then it's a
*method* in the subclass that overrides the base method.

Effectively providing the functionality the OP is after.
I don't know what that means.

That you can even generate those subclasses on the fly.

M4
 
A

anno4000

Martijn Lievaart said:
A class is a blueprint for the object,

No, that makes no sense. Some *method(s)* (the creator methods) belonging
to a class can be said to make up a blueprint. The class itself can
not accurately be described as a blueprint.
so it makes perfect sense to let
an object override the default provided by the class.

What are you saying? The OP didn't want to override a "blueprint" in
any sense, he wanted objects that behave differently when the same
method is invoked.
That's what I meant.

It's also what I gave an example for in my reply to the OP.

Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top