Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Re: Overridding subroutines called in private subroutines

by ikegami (Patriarch)
on Oct 05, 2008 at 05:13 UTC ( [id://715409]=note: print w/replies, xml ) Need Help??


in reply to Overridding subroutines called in private subroutines

You can't so much override a function as replace it.

use Module; # Execute module first so it doesn't replace you! BEGIN { package Module; no warnings 'override'; sub func { ... } }

Alternate syntax:

use Module; # Execute module first so it doesn't replace you! BEGIN { package Module; no warnings 'override'; *func = sub { ... }; }

You can wrap the original function:

use Module; # Execute module first so it doesn't replace you! BEGIN { package Module; no warnings 'override'; my $orig_func = \&func; sub func { ... $orig_func->(...) ... }; }

You can even do so temporarily:

use Module; # Execute module first so it doesn't replace you! { package Module; no warnings 'override'; my $orig_func = \&func; local *func = sub { ... $orig_func->(...) ... }; # Replaced from here. ... # Replaced until here. }

In all cases, it's replaced for everyone. You could use caller to emulate other behaviours, perhaps.

The only weirdness I can find in this module is that the absUrl subroutine is only called in MIME::Lite::HTML itself in private subroutines of the, "parse" method, like this:

There's no such thing as a private subroutine. The inner sub is just as public as the outer one. Whoever wrote that code was fooling himself. And he's asking for trouble. The following warning is an understated indicator of the problem of nesting named subs:

>perl -c -we"sub foo { my $x; sub bar { $x } }" Variable "$x" will not stay shared at -e line 1. -e syntax OK

I don't know if I've answered your question since I really don't know what you're asking, but I hope I helped.

Note: The BEGIN is not necessarily needed in any of the examples. Plain curlies would likely work too.

Replies are listed 'Best First'.
Re^2: Overridding subroutines called in private subroutines
by skazat (Chaplain) on Oct 05, 2008 at 05:53 UTC

    No - that's really helpful - the idea that I can just work within the namespace of the original module in my other script/module, by doin',

    { package Module; # Yadda Yadda, }
    I'm guessing the braces localize what I'm doing, so once outside them, I can do whatever I want. Just out of curiousity, would this do the same thing:
    package Module; package main; # And now back to our main script...

      would this do the same thing:

      If you had been in main initially, yes.

      Speaking of similar things, I didn't answer an earlier question.

      sub Foo::Bar::f {}

      is very similar to

      { package Foo::Bar; sub f {} }

      But the code is compiled in a different package. This affects caller and other things:

      use strict; use warnings; sub Foo::f { our $var; print(__PACKAGE__, "\n"); print("$var\n"); } { package Bar; sub f { our $var; print(__PACKAGE__, "\n"); print("$var\n"); } } $main::var = 'main!'; $Foo::var = 'foo!'; $Bar::var = 'bar!'; Foo::f(); # main # main! Bar::f(); # Bar # bar!
      I'm guessing the braces localize what I'm doing, so once outside them, I can do whatever I want.

      Be careful. The braces ({}) don't localize everything you are doing. The create a scope for your variables, but your package and subroutine declarations remain global. I think the form you used above gives a misleading impression that the package is block scoped.

      Update 2: Thanks for the heaping helping of crow, ikegami--I needed it. I was wrong. Dead wrong. See package. I read this wrong information somewhere, failed to check it, and have promulgated bogus information as a result.

      { package Foo; # Foo stuff # goes in here. } sub FooFunc { # This function is Foo::FooFunc! #actually it's not! It is in main. I was wrong. } package main; sub MainFunc { # This function is main::MainFunc. }

      That's the reason why I like this approach better:

      package Foo; { # Foo stuff # goes in here. } package main; # back in main.

      Update: After looking at the module, I'd be inclined to use ikegami's suggestion for using a localized override.

      This will minimize the spooky action at a distance factor.

      #!/usr/bin/perl use strict; use warnings; package Foo; sub method { routine(); } sub routine { return __PACKAGE__; } package Foo::Bar; our @ISA = qw( Foo ); sub routine { return __PACKAGE__; } sub method { no warnings 'redefine'; # Temporarily override routine() in the parent class. local *Foo::routine = \&routine; # Delegate to parent method. my $self = shift; $self->SUPER::method(@_); } package main; print "Foo: ", Foo->method, "\n"; print "Foo::Bar: ", Foo::Bar->method, "\n"; print "Foo: ", Foo->method, "\n";


      TGI says moo

        Be careful. The braces ({}) don't localize everything you are doing. The create a scope for your variables, but your package and subroutine declarations remain global.

        No, that's wrong. package is lexically scoped. That's why you don't have to switch it back after a module changes it.

        print(__PACKAGE__, "\n"); { package Foo; print(__PACKAGE__, "\n"); } print(__PACKAGE__, "\n");
        main Foo main

        It's really just a nit, but you're leaking an alias to @Foo::Bar::ISA. I also use BEGIN {} instead of {} inlined modules. I'd write your program as:

        #!/usr/bin/perl use strict; use warnings; BEGIN { package Foo; sub method { routine(); } sub routine { return __PACKAGE__; } } BEGIN { package Foo::Bar; our @ISA = qw( Foo ); sub routine { return __PACKAGE__; } sub method { no warnings 'redefine'; # Temporarily override routine() in the parent class. local *Foo::routine = \&routine; # Delegate to parent method. my $self = shift; $self->SUPER::method(@_); } } print "Foo: ", Foo->method, "\n"; print "Foo::Bar: ", Foo::Bar->method, "\n"; print "Foo: ", Foo->method, "\n";

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://715409]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (5)
As of 2024-04-25 10:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found