perl cyclic reference. Is this what is happening - perl

I am trying to write a daemon with perl. Now this daemon has the following code
sub b {
my $data;
if (some condition) {
$data->{"endsmeet"} = 1;
} else {
$data->{"endsmeet"} = 2;
}
my $newData = a($data);
}
sub a {
my ($data) = #_;
my %a = ();
my $newData = {
endsmeet => undef,
};
$a{"boo"} = $data->{"endsmeet"};
$newData->{"endsmeet"} = \%a;
return $newData;
}
My question is from the above, does the reference for %a go away and does it get cleaned up when b goes out of scope?

b returns the value of $newdata, which is a reference to an anon hash, which holds a reference to %a, which holds a scalar in the element with key boo.
If the value returned by b not stored, nothing will be referencing the value of $newdata, so it will get freed, so nothing will be referencing the anon hash, so it will get freed, so nothing will reference the scalar in the element with key boo, so it will get freed.
No cycles. No leak.

Related

Issue with classes "control"

so here's the thing.. I have one object that is responsable to create another different object, this created object can be destroyed or not (that depends on the user). The trick part is that the "creator" object is called again and if the other object wasnt destoyed, this class cant create this object again, but if the other object was destoyed, this class need to create again and the loop goes on.
i tried 2 solutions:
Global varible as "flag", it worked fine, but i got roasted for use global variable;
second was to make the destructor return a value to this flag, but i cant return from destructor.
Does yall know another way other than global variable?
Really appretiate the attention, cheers.
You didn't specify a programming language, so I'm going to assume Perl (with Moo as the OO toolkit).
Here's a possible implementation of what you're describing:
use v5.14.0;
use warnings;
package Item {
use Moo;
has _owner => (
is => 'ro',
weak_ref => 1,
clearer => 1,
);
sub detach {
my ($self) = #_;
if (my $owner = $self->_owner) {
$self->_clear_owner;
$owner->_clear_item;
}
}
sub BUILD {
my ($self) = #_;
say "!! constructing $self";
}
sub DEMOLISH {
my ($self) = #_;
say "!! destroying $self";
}
}
package Owner {
use Moo;
has item => (
is => 'lazy',
clearer => '_clear_item',
);
sub _build_item {
my ($self) = #_;
return Item->new(_owner => $self);
}
}
my $owner = Owner->new;
say "owner = $owner";
say "(1) owner->item = ", $owner->item;
say "(2) owner->item = ", $owner->item;
say "entering block {";
{
my $item = $owner->item;
say " (3) owner->item = $item";
$item->detach;
say " detached item = $item";
}
say "} leaving block";
say "(4) owner->item = ", $owner->item;
say "owner is still = $owner";
When I run this code, it produces the following output:
owner = Owner=HASH(0x23e52f8)
!! constructing Item=HASH(0x23e4950)
(1) owner->item = Item=HASH(0x23e4950)
(2) owner->item = Item=HASH(0x23e4950)
entering block {
(3) owner->item = Item=HASH(0x23e4950)
detached item = Item=HASH(0x23e4950)
!! destroying Item=HASH(0x23e4950)
} leaving block
!! constructing Item=HASH(0x23eb328)
(4) owner->item = Item=HASH(0x23eb328)
owner is still = Owner=HASH(0x23e52f8)
!! destroying Item=HASH(0x23eb328)
The idea is that the Owner class has an item attribute (which stores an instance of the Item class). This attribute is lazy, so it is only constructed on demand (the first time you use it).
As you can see by looking at the owner->item lines 1, 2, and 3, no new objects are constructed: $owner remembers its item.
However, it is possible to destroy item explicitly by calling $owner->item->detach. This is possible because each instance of Item has an (optional) _owner attribute; i.e. each item remembers its owner. This is a weak reference because otherwise we'd have a reference cycle (owner keeps item alive, item keeps owner alive).
When we call $item->detach, $item automatically removes itself from its owner (if it still has one). It is then automatically destroyed as soon as any other reference to it is gone (in the example, this happens when the local variable $item ceases to exist at the end of its block).
$owner, having been reset to its initial state, then automatically re-creates a new item the next time it is needed.

How can I return a whole hash map in Perl?

I have a hash called
%values
Now I want to return the whole hash in a subroutine
sub getvalues {
return $values;
}
But then I got an error, because $value needs a definition and my program stops. If I'm using
sub getvalues {
return %values;
}
it seems to work, but my program is very slow and don't get further... So how can I return the whole map?
It would be nice to return the hash reference instead of hash,what you need to do is
First stote the hash into the hash ref then return it like
sub getvalues {
my %values = (test => "SO");
my $values = \%values;
return $values;
}

Array of hashes not being passed by ref to sub

I have a setter sub setAssignmentStatus which takes an array of hashes (AoH from here on) and another parameter (do not concern yourself with this as that part works), and does something iterating through the AoH to set another entry in each hash element. It does not return anything because I want to use the same AoH object with the added entries after it is pulled through the setter sub and not construct a whole new AoH and repopulate the entries. Here is the setter:
sub setAssignmentStatus
{
my $fileFlatArySclr = $_[0];
my $cfgFile = $_[1];
#here I convert the AoH from the scalar necessary for the sub to its native form
my #fileFlatAry = #$fileFlatArySclr;
#this works, don't worry
my %cfgVarHash = getConfigVars($cfgFile);
foreach my $fileVarHashSclr(#fileFlatAry)
{
#convert each AoH entry from scalar necessary for iteration to native hash
my %varHash = %$fileVarHashSclr;
my $varName = $varHash{'VAR_NAME'};
my $asgnLineCnt = $varHash{'ASGN_CNT'};
my $asgnSts;
my $fileAsgnSts;
my $cfgAsgnSts;
if($asgnLineCnt > 0) { $fileAsgnSts = 1; } else { $fileAsgnSts = 0; }
my $cfgAsgnLine = $cfgVarHash{$varName};
if($cfgAsgnLine ne undef) { $cfgAsgnSts = 1; } else { $cfgAsgnSts = 0; }
$asgnSts = $fileAsgnSts.$cfgAsgnSts;
#debug to make sure $asgnSts is not null in the first place (it is not!)
print "\n*** setting ASGN_STUS of ".$varName." to ".$asgnSts;
#Here we set ASGN_STUS for every iteration
$varHash{'ASGN_STUS'} = $asgnSts;
}
}
It is called as follows:
setAssignmentStatus(\#fileFlatAry, $cfgFile);
However, after sending the #fileFlatAry AoH through setAssignmentStatus, each element hash does not contain an ASGN_STUS entry. Why is that and how can I fix it?
My suspicion is that I am doing something wrong with the \ modifier, which is how I am getting the data structure to be passed as a scalar parameter to the sub but I am not sure.
You modify %varHash instead of modyfing the referenced hash. Stop copying everything into local variables and modyfying the local variables.
$varHash{'ASGN_STUS'} = ...;
should be
$fileVarHashSclr->{'ASGN_STUS'} = ...;
I wouldn't do my #fileFlatAry = #$fileFlatArySclr; either. Pure waste.

Can't get values when looping over an array of arrays

I created an array like so:
while(#results = $execute->fetchrow())
{
my $active = 'true';
if($results[1] == 0)
{
$active = 'false';
}
my #campaign = ($results[0], $active);
push(#campaign_names, #campaign);
}
Later, when I need to access the name of the campaign (which is the first element of the campaign array), I can't seem to extract it. What is the proper syntax?
foreach $campaign (#campaign_names)
{
print ????;
}
Thanks!
The problem is you're pushing an array onto the end of #campaign_names, when what you want is an array reference. Here's how I'd write it:
while(#results = $execute->fetchrow())
{
my $active = $results[1] ? 'true' : 'false';
push #campaign_names, [ $results[0], $active ];
}
# later
foreach my $campaign( #campaign_names )
{
my $name = $campaign->[0];
my $active = $campaign->[1];
}
I've cleaned it up a bit by using a ternary conditional (?:) to figure out the value of $active. The [ ... ] constructs an anonymous array reference (a scalar pointing to an array) which is then pushed onto #campaign_names.
When we loop over those later, two important things to notice are that we use my in the loop variable to keep it local to the loop block, and that we use -> to dereference the elements in the array pointed to by the array reference.
That's not creating an array of arrays. my #campaign = ($results[0], $active); push(#campaign_names, #campaign); flattens and pushes $results[0] and $active into the #campaign_names array. Instead, push an arrayref:
my #campaign = ($results[0], $active);
push(#campaign_names, \#campaign);
or
my $campaign = [$results[0], $active];
push(#campaign_names, $campaign);
Arrays can only hold scalar values.
You'll want to refer to perldsc as you learn (perldoc perldsc, http://perldoc.perl.org/perldsc.html)

Shared Hashref of hashes possible?

Im trying to use a hashref of hashes to store a persistant field and a timestamp of when that field was changed.
It needs to be shared though as I have 2 threads that are required to access it although only one sets the values.
here is my current code with several commented out variations:
my $status = {};
share($status);
sub get_status {
my($raid) = #_;
return $status->{$raid}->{status} if exists $status->{$raid};
return 1;
}
sub set_status {
my($raid,$newstatus) = #_;
my %t;
$t{status} = $newstatus;
$t{timestamp} = Time::HiRes::time;
$status->{$raid} = \%t;
#$status->{$raid} = {
#status => $newstatus,
#timestamp => Time::HiRes::time()
#};
#$status->{$raid}->{status}=$newstatus;
#$status->{$raid}->{timestamp} = Time::HiRes::time;
return 1;
}
set_status('680','1');
get_status('680');
I continually get Invalid value for shared scalar at ./hashtest line 19.
Could anyone help please :D?
This perlmonks page should explain the problem. One of the posts claims:
You can share nested hash, as long as the internal hashes are also marked as shared.
You can try something like this:
share( %t );
$status->{ $raid } = \%t;