http://qs1969.pair.com?node_id=286426

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

Good Evening,

I do have a probably simple problem but I just can not fix it. Here is my point:

I have an own module (package) which is designed to create object-instances. In this package I have a "global" variable named %config. I put the word 'global' in quotation marks, because I think that's where my problem begins. I tried my, our and double-colon namespace syntax. This hash should be equal for all created objects. So far, so good. Every object is able to access %config. The package now contains a subroutine for reloading the (changed) config-file and storing its contents into %config after parsing. At this point the hash is either empty (or not accessible anymore?) for all object instances or did not change at all. That depends on how I declared the global hash. As you can see the sub-routine is the same as the one I call at the beginning of the package (to fill %config). I even tried almost-nonsense combinations in my desperation, but I am sure it is easily possible in any other way.

My program is very complex so I chose to post a simple (pseudo) takeout - The substantial is of importance for me. The _parse_file() sub-routine is purposely missing in order to keep clarity.
package Foo; use strict; my %config = _fill_config(); sub new { my $proto = shift(); my $status = shift() || 'normal'; my $package = ref($package) || $package; my $self = { status => $status }; bless($self, $package); return $self; } sub change_config { my $self = shift(); return unless $self->{status} ne 'admin'; %config = _fill_config(); } sub _fill_config { my %temp = _parse_file('config.cfg'); return %temp; }
Thank you very much for your suggestions, Monks.

BioHazard
reading between the lines is my real pleasure

Replies are listed 'Best First'.
Re: Changing package variable via object-instance
by liz (Monsignor) on Aug 25, 2003 at 17:48 UTC
    I can't see anything blatantly wrong. But looking at your node, several questions come up:
    Why not make %config set inside _fill_config?
    If the only way to set %config is by calling _fill_config, why don't you set %config directly in there?

    Are you using AutoLoader/SelfLoader/load?
    If you are, and _change_config/_fill_config are in the area that's not always loaded, they will not see the "same" package lexical (it will be a package global to them).

    Why the flattening?
    You realize of course that if you're returning a hash, you're essentially flattening it to a list and return that. From an effieciency point of view, it's much better to return a reference to a hash (and probably have the package lexical $config be a reference as well).

    Are you sure _parse_file works ok?
    Double check in _fill_config that actually the thing you expect, is being returned.

    I think there are other things going on in your example that I find strange. But for now I'll attribute those to the making of the (pseudo) takeout.

    Hope this helps

    Liz

Re: Changing package variable via object-instance
by bobn (Chaplain) on Aug 25, 2003 at 18:14 UTC

    If your instances are carrying around a reference to %config, excuting change_config overwrites %config. Objects may still be carrrying around a reference to the old %config.

    The code you posted doesn't seem to have this problem, though.

    --Bob Niederman, http://bob-n.com

    All code given here is UNTESTED unless otherwise stated.

Re: Changing package variable via object-instance
by herveus (Prior) on Aug 25, 2003 at 17:45 UTC
    Howdy!

    Is the sample code truly an extract from the non-working code? It appears to me that it should work fine, assuming _parse_file does the right thing.

    If you add _parse_file to your sample, try testing that to see if it works or not. If it works, add other bits to it incrementally until it breaks. Check the last thing you added...

    Good luck with sorting it out.

    yours,
    Michael

Re: Changing package variable via object-instance
by BioHazard (Pilgrim) on Aug 25, 2003 at 19:20 UTC
    Hi,

    Thanks for the quick replies. There's a mistake in the constructor in line 10. Must be $proto and not $package.

    The code I posted is not the code of my complex program. It is an equivalent piece that is in a symanticly point of view the same. I now tested it and it did not work. I changed flattening into references and it presented the same results to me: I changed the first line of config.cfg to option1=HASBEENCHANGED while sleep(15).

    FILE 'test.pl':
    use strict; use Foo; my $object = Foo->new('admin'); $object->show_config(); sleep(15); $object->change_config(); $object->show_config();
    FILE 'Foo.pm':
    package Foo; use strict; my $config = _parse_file(); sub new { my $proto = shift(); my $status = shift() || 'normal'; my $package = ref($proto) || $proto; my $self = { status => $status }; bless($self, $package); return $self; } sub change_config { my $self = shift(); return unless $self->{status} ne 'admin'; $config = _parse_file(); } sub show_config { foreach (keys(%{$config})) { print "KEY: $_\tVALUE: $$config{$_}\n"; } } sub _parse_file { my $filename = 'test.cfg'; my %temp; open(CONFIG, "<$filename") or die "can not open!\n"; while (<CONFIG>) { chomp($_); my ($key, $value) = $_ =~ m/^(\w+)=(.*)$/; $value ||= ''; $temp{$key} = $value if ($key); } close(CONFIG); return \%temp; } 1;
    FILE 'config.cfg':
    option1=value1
    option2=value2
    option3=value3
    
    Output:
    KEY: option1    VALUE: value1
    KEY: option2    VALUE: value2
    KEY: option3    VALUE: value3
    KEY: option1    VALUE: value1
    KEY: option2    VALUE: value2
    KEY: option3    VALUE: value3
    
    BioHazard
    reading between the lines is my real pleasure

      In test.pl:

      my $object = Foo->new('admin');

      In Foo.pm:

      sub change_config { my $self = shift(); return unless $self->{status} ne 'admin'; ... }

      change_config isn't doing anything if the status is equal to 'admin'. Try changing the status you're giving the object to something else.

      Also, you might want to look into using one of the Config::* modules (such as Config::INIFiles) for parsing your config file.

      bbfu
      Black flowers blossom
      Fearless on my breath