How could I redefine a subroutine and keep the old one too?
Asked Answered
R

3

7

Here's what I'd like to achieve:

sub first {
    print "this is original first";
}

*original_first = \&first;

sub first {
    print "this is first redefined";
}

original_first(); # i expect this to print "this is original first"
first() # i expect this to print "this is first redefined"

I thought that by saving the symbol for first, I'd be able to later call the original subroutine ( under the name original_first ) and to also be able to call first, and get the one redefined. However, if I call the original_first, I still get the "this is first redefined". What do I have to do to make this work?

Radiotelephone answered 3/12, 2009 at 21:44 Comment(0)
M
9

This should work as you expect:

sub first {
    print "this is original first";
}

*original_first = \&first;

*first = sub {
    print "this is first redefined";
};
Miranda answered 3/12, 2009 at 21:49 Comment(3)
Is it possible, when you redefine the first symbol, to affect only the code part?Radiotelephone
an assignment of a coderef (generated by sub{...}) to a typeglob will only replace the CODE entry in the glob. any other datatypes in the glob will not changeSchleswigholstein
You can also use local *first = sub {...}; to replace function within specific block only.Making
S
9

in your code, Perl interprets both sub declarations similar to this:

BEGIN {
    *first = sub { ... }
}

so both assignments to &first end up happening before saving the copy and calling the routines. the fix is to make the second declaration into a runtime assignment:

sub first {
    print "this is original first";
}

*original_first = \&first;

*first = sub {print "this is first redefined"};

original_first(); # prints "this is original first"
first();          # prints "this is first redefined"
Schleswigholstein answered 3/12, 2009 at 22:7 Comment(2)
citation needed for the sub {} -> BEGIN { *... } behaviour you describe.Arjan
i am inferring the above from the following explanation from perlmod: Subroutine definitions (and declarations, for that matter) need not necessarily be situated in the package whose symbol table they occupy. You can define a subroutine outside its package by explicitly qualifying the name of the subroutine: 1. package main; 2. sub Some_package::foo { ... } # &foo defined in Some_package This is just a shorthand for a typeglob assignment at compile time: 1. BEGIN { *Some_package::foo = sub { ... } }Schleswigholstein
L
1

See the Hook::LexWrap module, which can handle all of that for you. If you don't want to use the module, just look at the source, which shows you exactly how to do it.

Limestone answered 4/12, 2009 at 0:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.