does foreach (@list) alter @list??

H

Hendrik Maryns

Hi,
I've got this little program that reads all the files ending on .pos in
a directory into a list @dir, then opens them one by one, does
something, closes them again. When finished with all files, I start
this same thing for a second time, doing something different with the
files, based on what I did with them in the first loop. Now strangely
enough I get an error message which says there are uninitialised
variables in @dir, "Can't open etc."

I get this (with diagnostics):
Use of uninitialized value in open at test.pl li
ne 21 (#1)
(W uninitialized) An undefined value was used as if it were already
defined. It was interpreted as a "" or a 0, but maybe it was a
mistake.
To suppress this warning assign a defined value to your variables.

To help you figure out what was undefined, perl tells you what
operation
you used the undefined value in. Note, however, that perl
optimizes your
program and the operation displayed in the warning may not necessarily
appear literally in your program. For example, "that $foo" is
usually optimized into "that " . $foo, and the warning will refer to
the concatenation (.) operator, even though there is no . in your
program.

Uncaught exception from user code:
No such file or directory at test.pl line 21.
at test.pl line 21

If I redefine the @dir variable, it works, but this shouldn't be
necessary if you ask me...

Though of course you can't test this because you don't have those files
in your active directory, here's a reduced version:

use strict;
use warnings;
use diagnostics;

my @dir= <*.pos>; # feel free to change this for testing purposes

for (@dir){
open(my $in, '<', $_)||die($!);
# do something
close $in;
} #endfor

# @dir= <*.pos>;

for (@dir){
open(my $in, '<', $_ )||die($!);
#do something else
close $in;
} #endfor

So my question is: how come? Where does @dir get altered, or how come
$_ is undefined there.

For "do something" you could for example use

my $counter=0;
while (<$in>){$counter++;
print $counter, ' ';

Curious greetings, Hendrik
 
P

Peter Wyzl

: Hi,
: I've got this little program that reads all the files ending on .pos in
: a directory into a list @dir, then opens them one by one, does
: something, closes them again. When finished with all files, I start
: this same thing for a second time, doing something different with the
: files, based on what I did with them in the first loop. Now strangely
: enough I get an error message which says there are uninitialised
: variables in @dir, "Can't open etc."

<snip>:

: use strict;
: use warnings;
: use diagnostics;
:
: my @dir= <*.pos>; # feel free to change this for testing purposes
:
: for (@dir){
: open(my $in, '<', $_)||die($!);
: # do something
: close $in;
: } #endfor
:
: # @dir= <*.pos>;
:
: for (@dir){
: open(my $in, '<', $_ )||die($!);
: #do something else
: close $in;
: } #endfor
:
: So my question is: how come? Where does @dir get altered, or how come
: $_ is undefined there.
:
: For "do something" you could for example use

When if a foreach loop, the $_ variable is aliased to each element of the
array. Changing $_ in any way will change the corresponding variable in the
array.

What you are doing above is using the implicit $_ variable.

Since you don't include the actual 'do something' code I can't be _certain_
but from the sample you gave you are also using the $_ variable in the while
loop.

my $counter=0;
while (<$in>){ #### here $_ is repetitively set to the content of each line
of the file, thus changing @dir
$counter++;
print $counter, ' ';
}

It is probable that you have one ot more blank lines in one or more of the
files....

You either need to localise the $_ variable in the while loop or explicitly
declare and use a named variable in the foreach loop.

foreach my $file (@dar){
open (my $in, '<', $file) or die($!);
# do stuff
close $in;
}

etc etc etc

HTH

P
 
A

A. Sinan Unur

use strict;
use warnings;
use diagnostics;

my @dir= <*.pos>; # feel free to change this for testing purposes

for (@dir){
open(my $in, '<', $_)||die($!);
# do something
close $in;
} #endfor

# @dir= <*.pos>;

for (@dir){
open(my $in, '<', $_ )||die($!);
#do something else
close $in;
} #endfor

So my question is: how come? Where does @dir get altered, or how come
$_ is undefined there.

For "do something" you could for example use

my $counter=0;
while (<$in>){$counter++;
print $counter, ' ';

You might want to read perldoc perlsyn. Look for the section "Foreach
Loops".

When you have while(<$in>), $_ set to the line that was read from $in
each time. The loop terminates when no more lines can be read, and
hence, $_ is set to undef. Since $_ was an alias to an element of @dir,
that element is set to undef in return.

The simple solution to this is to use an explicit lexically scoped loop
variable, as in

for my $file (@dir) {

}

Sinan.
 
D

David K. Wall

Hendrik Maryns said:
use strict;
use warnings;
use diagnostics;

my @dir= <*.pos>; # feel free to change this for testing
purposes

for (@dir){
open(my $in, '<', $_)||die($!);
# do something
close $in;
} #endfor

If you do something to $_ inside this loop, then yes, that will alter
the current element of @dir. See the section on foreach loops in
perlsyn.

It's better to do something like this:

for my $d (@dir) {
# do stuff with $d
}

Then you don't have to worry about what you do to $_.
 
T

Tad McClellan

Hendrik Maryns said:
Subject: does foreach (@list) alter @list??


Not by itself. But it will if you ask it to.

Now strangely
enough I get an error message which says there are uninitialised
variables in @dir,

my @dir= <*.pos>; # feel free to change this for testing purposes

for (@dir){
open(my $in, '<', $_)||die($!);
# do something

So my question is: how come?


Can't tell, because you have not shown us what goes in
the "do something" there...

Where does @dir get altered,


Somewhere in the "do something" part.

For "do something" you could for example use

my $counter=0;
while (<$in>){$counter++;


You are using $_ in an outer foreach AND in an inner while.

The while will fail with $_ = undef.

Since $_ is also the loop control variable of a foreach(), it
serves as an alias back into the corresponding list element,
just as the "Foreach Loops" section in perlsyn.pod says it will.

Overusing $_ is abusing $_.

Choose some other name for one or the other of the loops.
 
I

ioneabu

[...]
Overusing $_ is abusing $_.

Choose some other name for one or the other of the loops.

my $counter=0;
while (<$in>){$counter++;
print $counter, ' ';

would something like this work? Maybe no better though:

for (my $i = <$in>; !$i; $i = <$in>) {print $i}


wana
 
M

Matt Garrish

Hendrik Maryns said:
my $counter=0;
while (<$in>){$counter++;
print $counter, ' ';

I never understand the fascination people have with running their own
unnecessary counters:

print "$. " while <$in>;

Matt
 
X

xhoster

Matt Garrish said:
I never understand the fascination people have with running their own
unnecessary counters:

print "$. " while <$in>;

What if I want to change "while (<$in>)" to "foreach (@in)"?
Or if I need to add something in the loop which deals with
some other file? Now for which file is $. accurate?

I'd rather type a few extra characters and just be done with it.

Xho
 
M

Matt Garrish

What if I want to change "while (<$in>)" to "foreach (@in)"?
Or if I need to add something in the loop which deals with
some other file? Now for which file is $. accurate?

And what if you were running your own counter and failed to account for the
obvious? Sorry if I don't see your point.

Matt
 
H

Hendrik Maryns

A. Sinan Unur schreef:
You might want to read perldoc perlsyn. Look for the section "Foreach
Loops".

When you have while(<$in>), $_ set to the line that was read from $in
each time. The loop terminates when no more lines can be read, and
hence, $_ is set to undef. Since $_ was an alias to an element of @dir,
that element is set to undef in return.

The simple solution to this is to use an explicit lexically scoped loop
variable, as in

for my $file (@dir) {

}

Sinan.

I understand now, thanks for pointing out!

Cheers, H.
 

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
474,432
Messages
2,571,681
Members
48,796
Latest member
Greg L.

Latest Threads

Top