Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister

The correct way to redefine a routine

by punkish (Priest)
on Mar 28, 2008 at 17:38 UTC ( #677065=perlquestion: print w/replies, xml ) Need Help??

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


I install Foo:Bar from CPAN (perl -MCPAN -eshell, etc.). I write my code --

my $baz = Foo::Bar->new(); $baz->do_magic;

Then I discover that $baz->do_magic does about 90% of what I want. So, I want to modify it, but I don't want to tinker with the Foo::Bar code. I do the following in my package.

package My::Package; .. lots of code .. package Foo::Bar; # my version of do_magic sub do_magic { } # end of my tinkering with Foo::Bar 1;

Question: Is this the right way? Perl does complain and tell me that do_magic has been redefined, but yeah, that's what I did. If this is not a good way, what is the better way?


when small people start casting long shadows, it is time to go to bed

Replies are listed 'Best First'.
Re: The correct way to redefine a routine
by Fletch (Bishop) on Mar 28, 2008 at 17:49 UTC
    package My::Foo::Bar; use base 'Foo::Bar'; sub do_magic { my $self = shift; my $orig_ret = $self->SUPER::do_magic( @_ ); ### Do rest of magic here. return $actual_ret_value; }

    Season accordingly if your magic needs to be done before the superclass' magic.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: The correct way to redefine a routine
by pc88mxer (Vicar) on Mar 28, 2008 at 17:51 UTC
    That will work, but... do any any other modules call Foo::Bar::do_magic, and will they work with your tinkered version? This includes the module Foo::Bar itself as well as any modules you are currently using or may use in the future. For instance, if Foo::Bar is a CPAN module, redefining do_magic can break a lot of things if your use another module which depends on the original version of the subroutine.

    It is better to use sub-classing if you can:

    package My::Foo::Bar; @ISA = qw(Foo::Bar); sub do_magic { ... } # tinker here
    and then use My::Foo::Bar instead of Foo::Bar. Now the original do_magic is preserved for those other modules which need it.

    Update: use base ... is better than setting @ISA, but they accomplish the same thing.

Re: The correct way to redefine a routine
by Narveson (Chaplain) on Mar 28, 2008 at 18:04 UTC

    I concur with the subclassing advice you've already received.

    But if you want to ignore the warning, you can say

    no warnings 'redefine';
Re: The correct way to redefine a routine
by dragonchild (Archbishop) on Mar 28, 2008 at 19:48 UTC
    One possibility is instead of overriding the original do_magic(), go ahead and create my_do_magic() and put it in either My::Foo::Bar or within Foo::Bar itself.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: The correct way to redefine a routine
by Anonymous Monk on Mar 29, 2008 at 06:14 UTC
    You must look at the Sub::Install Module and the reinstall() function in that package. Very Neat
Re: The correct way to redefine a routine
by jsegal (Friar) on Apr 02, 2008 at 22:27 UTC
    Like many things in Perl, there is more than one way to do it. Others in this thread have suggesting subclassing, which sometimes works, sometimes doesn't. For instance, suppose you are using class A which instantiates class B, and it is the method in class B that you need to override, even for your use of class A. Though you could in theory override class A to have the method in question instantiate your overriding class B, perl does let you do change class B's method directly.

    Be warned that doing this sort of thing may be fraught with danger, especially if you upgrade the class whose method you are overriding, or if other classes you use call that method and depend on the old behavior. But if you go in with your eyes open and are aware of these issues, here are a couple of other ways to meet this goal:

    package main; sub new_foobar_magic { my ($self,@otherargs) = @_; ... } *Foo::Bar::do_magic = \&new_foobar_magic; # or in one swoop: *Foo::Bar::do_magic = sub { my ($self,@otherargs) = @_; ... } # if you want to call the old routine: my $old_foobar_magic = \&Foo::Bar::do_magic; *Foo::Bar::do_magic = sub { my ($self,@otherargs) = @_; ... adjust things or log things ... $old_foobar_magic->($self,@args); };


Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://677065]
Approved by Corion
Front-paged by derby
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (4)
As of 2022-08-17 16:23 GMT
Find Nodes?
    Voting Booth?

    No recent polls found