in reply to Altering Package Subs and Running In To Problems

To get run-time behavior, replace your "use MyCoolModule" with "require MyCoolModule; import MyCoolModule;" which does the same thing but after your subroutines have been defined.

For what it's worth, the fact that your tree is standing on its head doesn't mean you can't use inheritance. I'm using multiple inheritance to generate subclasses on demand with different sets of mixin classes; see Solving the SUPER problem in Mixins with a Dispatch Method.

  • Comment on Re: Altering Package Subs and Running In To Problems

Replies are listed 'Best First'.
Re^2: Altering Package Subs and Running In To Problems
by Bovine (Initiate) on Nov 11, 2004 at 09:44 UTC

    Hmm... really good idea.
    Maybe there still is a way to use 'use' (or one line and still keep it at the top)?
    I was also thinking of playing around with the BEGIN, INIT, etc. subs in my Plugin class and seeing if anything like that worked.

    Even though the dispatch-ness sounds pretty cool, my goal is to have the base module have all the subs.
    Lets say package Foo (base) uses Bar (child) as a plugin. Foo's subs would be overwritten by Bar's (limited by, say, an export hash like Exporter uses), thus letting Foo's subs transparently point to Bar's.
    Perl code probably explains this better...

    foreach (@Bar::PLUGIN_SUBS) { # error checking and the like *{"Foo::$_"} = \&{"Bar::$_"}; }
    So I could call Foo::something, but actually (permitting Bar does plug into the 'something' subroutine) Bar::something would be called. Kind of like flattening a tetris board (without the falling pieces) such that, at the end, only the blocks that were originally at the top are now lining the bottom.
    (hope that made sense)

      I tested and doing it in INIT works as you'd expect: import is called when the module is used, thereby replacing the function before the base one being replaced is defined. So the base ends up replacing the plug-in. But INIT is called right before execution so it does the job.

      Regarding the evilness of this: Playing around like this is one of the ways I learned how Perl works. You will no doubt experience several lightbulbs going on as try different approaches, which is a good thing. Just think about your clients, the interfaces they use, and how much you may be bending standard views of the world before you turn what you play with into production code.

        Ah, cool. Thanks!

        Yeah, i understand. Im not really expecting this to become widespread, i just think its an interesting idea.

        Thanks again.

        Correct me if im wrong, but INIT is run once, correct?
        If multiple 'use's to Plugin.pm are made, then do problems arise?

      Ahhhh, this code explains it. You're not wanting to step on toes, you're wanting your users to step on YOUR toes!

      Another thing to consider, is using the Safe module (with everything turned on perhaps) to load the plugins into a certain namespace. And then use that namespace for the parts of your code you want the plugins to overwrite. That way, you can even still publish an interface, but each plugin can only see the plugin-accessible part of the namespace.

      use Safe; my $cpt = Safe->new( 'PluginNamespace' ); $cpt->deny_only(); $cpt->rdo( PLUGINFILENAME );
      And then the plugin doesn't have to mess with PluginNamespace, that happens automatically. You can even pass things in (which is as if the plugin got them from you with export. Like a reverse export) and other crazy stuff.

      I use Safe alot, but rarely for what it was intended for...


      --
      Snazzy tagline here

        Hmm, sounds like it might work. I'll look into that.
        Thanks.

      Even though the dispatch-ness sounds pretty cool, my goal is to have the base module have all the subs.

      Understood. The advantage of using method dispatch over stash mangling is that you can have multiple instances which don't conflict.

      package Foo; sub shared { print "Shared method" } sub foozle { print "Foo's foozle" } package Bar; sub foozle { print "Bar's foozle" } package Blip; sub foozle { print "Blip's foozle" } package FooBar; @ISA = qw( Bar Foo ); package FooBlip; @ISA = qw( Blip Foo );

      With that kind of setup, you can choose which set of plugins you want to have active, and can have one part of your code use one plugin while another part does not.

      package main; $package = 'Foo'; $package->shared(); $package->foozle(); # Calls Foo's foozle $package = 'FooBar'; $package->shared(); $package->foozle(); # Calls Bar's foozle

      This approach also lets you dynamically stack your "plugins" so that a method in one of them can call NEXT and get the results of the next method up the chain; see my earlier article for details of this technique.

        Interesting, but not exactly what im looking for.

        Editing your code, I'd like something like this:
        (i get the multiple inheritance part, but the functionality is different, top-most subs are not accessed through the base module)

        package Foo; use Plugin 'Bar'; sub shared { print "Shared method" } sub foozle { print "Foo's foozle" } package Bar; our @PLUGIN_SUBS = qw(foozle); sub foozle { print "Bar's foozle" } # omitting Blip.. #package Blip; #sub foozle { print "Blip's foozle" } #======================= package main; $package = 'Foo'; $package->shared(); $package->foozle(); # Calls ***Bar's*** foozle
        From what i see theres no other way to have things work that way.

        Now this doesnt allow for having two instances of a plugin tree with the same base (at the moment), unfortunately.