references => how not to destroy my data ?

J

Jan

Hi,

I'm struggling with references again. Underneath you will find a code
snippet with some comments interleaved to tell what's going on.

# start code snippet.

$recordIndex = 0;

open (GROUPS, "<groupsfile.txt") or die "Cannot open $groupsFile\n";
while ($line = <GROUPS>)
{
@juniorMembers = ();
@seniorMembers = ();

#
# Snipped away code in which the two preceding arrays are populated
and in which
# which $group gets a valid value. This code was tested and correct.
So for
# keeping things easy I'll leave this 'huge' part out...
#

foreach $juniorMember(@juniorMembers)
{ push( @{$juniorArray}, $juniorMember) ; }
foreach $seniorMember(@seniorMembers)
{ push( @{$seniorArray}, $seniorMember) ; }

# Since I'm in while loop I try to store my data into an anonymous
# array by using a hard reference (e.g. $juniorArray)

$myrecord = { GROUP => $group,
JUNIOR => $juniorArray,
SENIOR => $seniorArray };

$database[$recordIndex++] = $myrecord;
}

# End code snippet.

Next thing I know, for each record I have in my 'database' array, when
dereferencing the arrays, about the same array contents. I do know
that I do overwrite my references to the arrays, but hoped that would
have been solved by storing these references in the anonymous hash.
dumb, dumber...

So perl doesn't know the location of my 'junior' and 'senior' arrays
data anymore, I guess. Can someone offer some advice on more proper
ways to come out of this while loop with the array data still intact ?

Hoping I stated the problem correctly,
Jan
 
G

Glenn Jackman

Jan said:
foreach $juniorMember(@juniorMembers)
{ push( @{$juniorArray}, $juniorMember) ; }
foreach $seniorMember(@seniorMembers)
{ push( @{$seniorArray}, $seniorMember) ; }

$myrecord = { GROUP => $group,
JUNIOR => $juniorArray,
SENIOR => $seniorArray };

Perhaps:
$myrecord = {
GROUP => $group,
JUNIOR => [ @juniorMembers ],
SENIOR => [ @seniorMembers ],
};
 
B

Benjamin Goldberg

Jan said:
Hi,

I'm struggling with references again. Underneath you will find a code
snippet with some comments interleaved to tell what's going on.

# start code snippet.

$recordIndex = 0;

open (GROUPS, "<groupsfile.txt") or die "Cannot open $groupsFile\n";
while ($line = <GROUPS>)
{
@juniorMembers = ();
@seniorMembers = ();

Are these used after this loop? If not, then lexically scope them.

my (@juniorMembers, @seniorMembers);

They will be automatically initialized with ().
#
# Snipped away code in which the two preceding arrays are populated
and in which
# which $group gets a valid value. This code was tested and correct.
So for
# keeping things easy I'll leave this 'huge' part out...
#

foreach $juniorMember(@juniorMembers)
{ push( @{$juniorArray}, $juniorMember) ; }
foreach $seniorMember(@seniorMembers)
{ push( @{$seniorArray}, $seniorMember) ; }

What is put into $juniorArray and $SeniorArray before this? If nothing,
or if only [], then you could do:

$juniorArray = \@juniorMembers;
$seniorArray = \@seniorMembers;

This of course will only work right if @juniorMembers and @seniorMembers
are lexically scoped to the loop with my(). If you leave out the my(),
and keep your old @juniorMembers = (); @seniorMembers = ();, then of
course simply taking references to them won't work quite right.
Instead, you would have to do either what you have, or else one of:

$juniorArray = [@juniorMembers];
$seniorArray = [@seniorMembers];

Or:

push @$juniorArray, @juniorMembers;
push @$seniorArray, @seniorMembers;
# Since I'm in while loop I try to store my data into an anonymous
# array by using a hard reference (e.g. $juniorArray)

$myrecord = { GROUP => $group,
JUNIOR => $juniorArray,
SENIOR => $seniorArray };

$database[$recordIndex++] = $myrecord;

Is $recordIndex ever anything other than one-past-the-end of @database?

If not, then this could be written as:

push @database, $myrecord;

And dispense with $recordIndex entirely.
}

# End code snippet.

Next thing I know, for each record I have in my 'database' array, when
dereferencing the arrays, about the same array contents.

Not just that... you probably have the same *arrays*, not just the same
contents.
I do know that I do overwrite my references to the arrays, but hoped
that would have been solved by storing these references in the
anonymous hash.
dumb, dumber...

So perl doesn't know the location of my 'junior' and 'senior' arrays
data anymore, I guess. Can someone offer some advice on more proper
ways to come out of this while loop with the array data still intact ?

Rewrite the code something like this:

use strict; # always use strict!
use warnings; # always use warnings (or else, -w on #! line)!
open( my($groups), "<", "groupsfile.txt" )
or die "Couldn't open groupsfile.txt: $!";
my @database;
while( my $line = <$groups> ) {
my (@juniorMembers, @seniorMembers);
# put stuff in @juniorMembers and @seniorMembers from $line.
push @database, {
GROUP => $group,
JUNIOR => \@juniorMembers,
SENIOR => \@seniorMembers,
};
}
close $groups;
# process @database

[untested]
 
J

Jan

Benjamin Goldberg said:
Jan said:
Hi,


$recordIndex = 0;

open (GROUPS, "<groupsfile.txt") or die "Cannot open $groupsFile\n";
while ($line = <GROUPS>)
{
@juniorMembers = ();
@seniorMembers = ();
#
# Snipped away code in which the two preceding arrays are populated
and in which
# which $group gets a valid value. This code was tested and correct.
So for
# keeping things easy I'll leave this 'huge' part out...
#

foreach $juniorMember(@juniorMembers)
{ push( @{$juniorArray}, $juniorMember) ; }
foreach $seniorMember(@seniorMembers)
{ push( @{$seniorArray}, $seniorMember) ; }

What is put into $juniorArray and $SeniorArray before this? If nothing,
or if only [], then you could do:

$juniorArray = \@juniorMembers;
$seniorArray = \@seniorMembers;

This of course will only work right if @juniorMembers and @seniorMembers
are lexically scoped to the loop with my(). If you leave out the my(),
and keep your old @juniorMembers = (); @seniorMembers = ();, then of
course simply taking references to them won't work quite right.
Instead, you would have to do either what you have, or else one of:

push @$juniorArray, @juniorMembers;
push @$seniorArray, @seniorMembers;
# Since I'm in while loop I try to store my data into an anonymous
# array by using a hard reference (e.g. $juniorArray)

$myrecord = { GROUP => $group,
JUNIOR => $juniorArray,
SENIOR => $seniorArray };

$database[$recordIndex++] = $myrecord;
}

# End code snippet.

Next thing I know, for each record I have in my 'database' array, when
dereferencing the arrays, about the same array contents.

Not just that... you probably have the same *arrays*, not just the same
contents.

Correct ! I get the same arrays *and* their contents are wrong. (see
further on...)
I do know that I do overwrite my references to the arrays, but hoped
that would have been solved by storing these references in the
anonymous hash.
dumb, dumber...

So perl doesn't know the location of my 'junior' and 'senior' arrays
data anymore, I guess. Can someone offer some advice on more proper
ways to come out of this while loop with the array data still intact ?

Rewrite the code something like this:

use strict; # always use strict!
use warnings; # always use warnings (or else, -w on #! line)!
open( my($groups), "<", "groupsfile.txt" )
or die "Couldn't open groupsfile.txt: $!";
my @database;
while( my $line = <$groups> ) {
my (@juniorMembers, @seniorMembers);
# put stuff in @juniorMembers and @seniorMembers from $line.
push @database, {
GROUP => $group,
JUNIOR => \@juniorMembers,
SENIOR => \@seniorMembers,
};
}
close $groups;
# process @database

[untested]

I tested it for you ;-) (well, most part of it...), and you provided
the (sorry - a - ) correct solution. I couldn't see anything wrong in
my code. If possible (you helped me out already), could you explain
me or refer me to the proper documentation on where my solution went
wrong where yours is correct ? I'm eager to learn about what seems to
be my misunderstanding of scope...

Thanks for helping out !
Jan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top