Issue with classes "control" - class

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.

Related

Access an array item in Perl after generating that array

Hello I want to access an specific array item based in a condition previously checked. I leave the code here:
elsif (scalar(#{$boss->bosses}) > 1) {
foreach my $pa (#{$boss->bosses}) {
my $p = My::Model::Group->new(id => $pa->group_id);
push(#$groups, $p);
$valid_pass = 1 if ($pa->checkPassword($self->param('password')));
}
if ($valid_pass) {
my $pa_id = $pa->id;
my $pa_partner_id = $pa->group_id;
}
else {
}
}
What I want to do is, if that if in the array that comes, I check if the password is correct, so if it's correct, then I want to take the id and the group_id of the array item to use it in a function to be able to log them in.
Your for loop is doing two things at once: producing a list of My::Model::Group objects in #$groups, and finding the first boss whose password checks out.
I suggest that you split them up into two clear operations, and the List::Util modules first operator is ideal for the second task
Here's how it would look. I've extracted the result of the method call $boss->bosses into a variable $bosses to avoid repeated calls to the method
Note that you don't need to apply scalar to an array when checking its size. The > and all the other comparators impose scalar context anyway
I've taken much of my code from your question, and I'm a little concerned that you extract values for $pa_id and $pa_partner_id and then just discard them. But I imagine that you know what you really want to do here
use List::Util 'first';
my $bosses = $boss->bosses;
if ( ... ) {
...;
}
elsif ( #$bosses > 1 ) {
#$groups = map { My::Model::Group->new( id => $_->group_id ) } #$bosses;
my $password = $self->param( 'password' );
my $pa = first { $_->checkPassword( $password ) } #$bosses;
if ( $pa ) {
my $pa_id = $pa->id;
my $pa_partner_id = $pa->group_id;
}
else {
...;
}
}

List instance object of a class

In Perl, is it possible to list all objects of a specific class?
For example, I have two objects of class Character:
my $char1 = Character->new('John');
my $char2 = Character->new('Adam');
Now, I want to iterate over all Character objects ($char1 and $char2), like :
foreach ( "objects Character" ) {
print "$_->getName()\n";
}
No, Perl doesn't maintain a list of objects by class. You'll need to keep track of this yourself.
If you have a fixed number of objects:
my $char1 = Character->new('John');
my $char2 = Character->new('Adam');
for ($char1, $char2) {
print $_->getName(), "\n";
}
If you have a variable number of objects:
my #chars;
push #chars, Character->new('John');
push #chars, Character->new('Adam');
for (#chars) {
print $_->getName(), "\n";
}

perl cyclic reference. Is this what is happening

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.

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.

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;