Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Can you override lexically scoped variables when sub-classing a module.

by learnedbyerror (Monk)
on Oct 11, 2012 at 18:45 UTC ( [id://998513]=perlquestion: print w/replies, xml ) Need Help??

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

Oh Monks, I am in need of your assistance again. I am trying to sub-class a module that makes of a lexical (my) variable set at the package level. I need to change the change the value of this variable in my module; however, I cannot figure out how to do this.

The following code is representative of the other module and what I would like to do.

package p1; my $var1 = 'var1-p1'; sub new { my $class = ref $_[0] ? ref shift : shift; my $self = {}; bless $self, $class; return $self; } sub get_var1 { return $var1; } 1;

My desired approach - which won't work as shown - is something like this:

package p2; use p1; our @ISA=qw(p1); sub set_var1 { my $self = shift; my $new_var1 = shift; $var1 = $new_var1; return $var1; } 1;

An example of using these modules is:

use p2; my $obj = p2->new(); say $obj->get_var1() . "\n"; say $obj->set_var1('changed') . "\n"; say $obj->get_var1() . "\n"

With the desired output being:

var-p1 changed changed

Any assistance in figuring out a way around this conundrum short of modifying the first module would be greatly appreciated. Having said that, I am trying to to get the first module modified to include constructors for changing this variable.

As always, thanks in advance for your assistance!

lbe

Replies are listed 'Best First'.
Re: Can you override lexically scoped variables when sub-classing a module.
by ELISHEVA (Prior) on Oct 11, 2012 at 21:02 UTC

    Why are you opposed to changing the original code? Is this a third party provided file so that your changes will be wiped out by the latest update? If so, that might be a good reason - PROVIDED that you document a hack using PadWalker very carefully with lots of asterisks and capital letters or other PAY ATTENTION TO ME signs in the code that uses. Anything private to a third party module is likely to get renamed, reengineered, restructured, or otherwise disappeared. Despite your goal of not touching third party code, your hack may still break with the next release of the third party code.

    If this is internal company code, then you really are better off getting permission to change "my" to "our", even though it is major hassle. The problem with hacks like using PadWalker is that they are virtually impossible for the next programmer to discover who has your job after you. Anyone reading the source code of the file with the "my" variable will reasonably expect that variable not to be vulnerable to being messed with by outside modules. They will be going nuts trying to figure out what in the original module is making it change (nothing of course) they will NEVER think to look elsewhere outside of the file in the many company scripts to find your module playing hack with PadWalker. "my" is like a contract with future maintainers that outsiders won't muck with this.

    Of course if the pesky module with "my" is yours and yours alone, then again why NOT change it to "our"?

      I'm not opposed to changing the original code. It is a 3rd party and I have a request out. Eventually, it will get done, just not as fast as I would like. I have been looking at Padwalker and considering it. However, my gut is telling me that this isn't a "good" path for all of the reasons that you pointed out.

      Given your feedback and the feedback from the other monks, I think I am going to create a patched local copy and then sub-class it. This will minimize the impact on the maintenance to reverse out when changed.

      Thanks! lbe

Re: Can you override lexically scoped variables when sub-classing a module.
by tobyink (Canon) on Oct 11, 2012 at 20:07 UTC

    Not really, no. That's kind of the point of lexical variables. They can't be accessed from outside their scope, so they are immune to "spooky action at a distance".

    It's a bit of a hack, but you might have some luck with PadWalker's set_closed_over.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      Thanks, I'll take a look at it. I had looked at Padwalker earlier but didn't get deep enough with it to figure out how to apply it to the module in question

      lbe

Re: Can you override lexically scoped variables when sub-classing a module.
by jandrew (Chaplain) on Oct 11, 2012 at 19:50 UTC

    It may be that Moose is a framework you would like

    Package 1

    package p1; use Moose; has 'var1' => ( is => 'ro', reader => 'get_var1', default => 'var1-p1', ); 1;

    Package 2

    package p2; use Moose; extends 'p1'; has '+var1' =>( writer => 'set_var1', ); 1;

      I don't like Moose, I LOVE Moose!!!

      But, I am trying to find a solution that does not require changes to the p1 code - if it is possible.

      If worse comes to worse and I have to refactor the p1 module, then in all likelihood it will be reworked with Moose.

      Thanks, lbe

        Well if you can change the 'my' to 'our' in p1 then this works

        Package 1

        package p1; our $var1 = 'var1-p1';#Note the change my->our sub new { my $class = ref $_[0] ? ref shift : shift; my $self = {}; bless $self, $class; return $self; } sub get_var1 { return $var1; } 1;

        Package 2

        package p2; use p1; our @ISA=qw(p1); sub set_var1 { my $self = shift; my $new_var1 = shift; $p1::var1 = $new_var1; return $p1::var1; } 1;

        You get a global variable that you may not want

Re: Can you override lexically scoped variables when sub-classing a module.
by nikosv (Deacon) on Oct 12, 2012 at 17:31 UTC
    doesn't this defeat the whole point of encapsulation ?
Re: Can you override lexically scoped variables when sub-classing a module.
by lamprecht (Friar) on Oct 12, 2012 at 17:50 UTC

    Does p1 access $var1 directly? Otherwise you could override get_var1. (Possibly with a default SUPER call unless it has been set in p2).

    Cheers

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (3)
As of 2024-04-19 20:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found