List instance object of a class - perl

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";
}

Related

How to split string by comma into a hash in Perl?

I have the following code:
my #logs = split(",",$opts->{"logs"});
$opt_href->{"logs"} = \#logs;
It basically splits the $opts->{"logs"} by comma and keeps the array ref. Later I need to check if string exists in the $opt_href->{"logs"} array. Looking at this topic, I see that it's recommended to keep a hash, instead of array. I could just do:
my %logs;
for each my $log (split(",",$opts->{"logs"})) {
$logs{$log} = 1;
}
$opt_href->{"logs"} = \%logs;
Is there a better way to do this? Maybe a one/two liners?
my %logs = map { $_ => 1 } split /,/, $opts->{logs};
$opt_href->{logs} = \%logs;
Or, using the anonymous hash reference, constructed by { }
$opt_href->{logs} = { map { $_ => 1 } split /,/, $opts->{logs} };

how can i Create indexed variable in perl?

I am new to perl, how can i create indexed variable like $Num0, $Num1 and $value0, $value1. I have to store some value from hash in this variable.
$Num0 = $req->{value0};
$Num1 = $req->{value1};
$Num2 = $req->{value2};
is it possible to crate both variable Num0,Num1 and value0,value1 using some logic based on indexing like below.
while($i < 5)
{
$Num.$i = $req->{value$i};
}
You can use perl arrays.
my #num;
my $i=0;
while ($i<5) {
$num[$i] = $req->{"value$i"};
$i++;
}
See perl cheatsheet for concise help on perl.
#ikegami suggested some alternative ways to do the same thing in comments:
my #num = map { $ref->{"index$_"} } (0..4);
and
my #num;
for my $i (0..4) {
push #num, $ref->{"index$i"};
}
See help on map and push.

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.

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)