views:

184

answers:

3

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?

+9  A: 

This should work as you expect:

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

*original_first = \&first;

*first = sub {
    print "this is first redefined";
};
Lukáš Lalinský
Is it possible, when you redefine the `first` symbol, to affect only the code part?
Geo
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 change
Eric Strom
You can also use `local *first = sub {...};` to replace function within specific block only.
Ivan Nevostruev
+8  A: 

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"
Eric Strom
Nice explanation. Thanks!
Geo
citation needed for the `sub {}` -> `BEGIN { *... }` behaviour you describe.
Ether
Eric Strom
+1  A: 

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.

brian d foy