Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unwanted clearing of array member when used as name of a file to be Read-opened (reach of EOF ???) #6034

Closed
p5pRT opened this issue Oct 24, 2002 · 7 comments

Comments

@p5pRT
Copy link

p5pRT commented Oct 24, 2002

Migrated from rt.perl.org#18073 (status was 'resolved')

Searchable as RT18073$

@p5pRT
Copy link
Author

p5pRT commented Oct 24, 2002

From Jean-Luc.VERIT@turbomeca.fr

Hello
Here is a non logical behaviour (to my eyes) of Perl when I used an array of names of files that I want to read.
I want to open and read all of them using

  for(@​myArray){ ... open FIL,$_ ... read it with while(<FIL>){ ......} }

I don't modify the Array with a line of code, and when the loop finishes, all values of @​myArray are null strings.

I give you an example of this with 6 options : 'A','B', ... , 'F'
It seems that the fact that the End of File is reached or not is a Key-point.
I tested it with 3 files in @​myArray on 2 systems​:
Unix​: Sun ultra Sparc 5 with Solaris binary distribution : nsperl5.005_03-10-sun4-solaris.tar.gz
  PC​: windows binary distribution : ActiveState version 005.03_02

with
  @​myArray = ( 'fa.c' , 'fb.c' , 'fc.c' )

Here are the results I got (the sames on the 2 systems)

case A @​myArray = ( '' , '' , '' )
case B @​myArray = ( 'fa.c' , 'fb.c' , 'fc.c' )
case C @​myArray = ( 'fa.c' , '' , '' )
case D @​myArray = ( '' , 'fb.c' , 'fc.c' )
case E @​myArray = ( 'fa.c' , 'fb.c' , 'fc.c' )
case F @​myArray = ( 'fa.c' , 'fb.c' , 'fc.c' )

Comments in Perl script give more informations​:

Hoping that I don't waste your time; Faithfully
Jean-Luc.Verit@​turbomeca.fr
==================================================>>>>>>>>>>>>>>>>>>>

#!/bin/Perl -w

# Why the content of an array is (partially) cleared when it is used to
# contain the names of files to be read, when no modification is done to
# the array ?

# It seems that that the fact that the End Of File is reached or not is
# an important thing in that behaviour.

# This behaviour seems to me very strange..

# This was run on Unix and PC with identical behaviour

# Unix​: Sun ultra Sparc 5 with Solaris System
# binary distribution :
# nsperl5.005_03-10-sun4-solaris.tar.gz
# PC​: under windows NT4
# binary distribution :
# ActiveState version 005.03_02

# It is difficult for me to install new versions as 5.5, or 5.6
# unless the dysfunctionment is fixed in newer versions

# HERE IS THE CODE SHOWING THE PROBLEM
# 6 choices are possible with results in file 'toto.txt'.
# It needs to have at least 2 (3 is better) text files of more than 2 lines each
# In this exemple function 'litDir' is looking for files
# in the same directory of this test-file,
# and the name of which finished with '.c'

  $choice = 'A';

%txtChoice =(
'A' ,'reads all files until EndOfFile is reached',
'B' ,'reads only first line of each file',
'C' ,'first line of first file then all lines of other files',
'D' ,'all line of first file then 1 line of other files',
'E' ,'all lines of all files with a C-Style for',
'F' ,'all lines of all files with, @​A is saved then restored'
);

unless($h = $txtChoice{$choice}){
  print "no Valid Choice​: '$choice'!\nHit a key\n";
  $h = <STDIN>; # for use with double clic on PC NT4
  die "no Valid Choice​: '$choice'!";
  }

&litDir(\@​A); # reads a list of files according to some specifications

open FOU,">toto.txt";
print FOU "Choice : $choice\t$h\n\n";

# Prints the content of @​A before we use it
# --------------------------------------------------------
for(@​A){ print FOU "Before​:file​:$_​:\n"}

$h = 'File000';

if($choice eq 'A'){
#=================== reads all files until EndOfFile is reached
  for(@​A){
  $h++; print FOU "$h\t>$_<\tchoice $choice\n";
  $fic = $_;
  open FIC, $fic or die "Cant't read >$fic< $!";
  while(<FIC>){ chomp; } # just reading all lines
  }
  }
elsif($choice eq 'B'){
#=================== reads only first line of each file
  for(@​A){
  $h++; print FOU "$h\t>$_<\tchoice $choice\n";
  $fic = $_;
  open FIC, $fic or die "Cant't read >$fic< $!";
  $t = <FIC>;
  }
  }

elsif($choice eq 'C'){
#=================== reads first line of first file
# then reads all other files until EndOfFile is reached
  $flag = 1;
  for(@​A){
  $h++; print FOU "$h\t>$_<\tchoice $choice\n";
  $fic = $_;
  open FIC, $fic or die "Cant't read >$fic< $!";
  if($flag){ $t = <FIC> ;$flag = '';}
  else{ while(<FIC>){ chomp; } }
  }
  }

elsif($choice eq 'D'){
#=================== reads first file until EndOfFile is reached
# then reads only first line of all other files
  $flag = 1;
  for(@​A){
  $h++; print FOU "$h\t>$_<\tchoice $choice\n";
  $fic = $_;
  open FIC, $fic or die "Cant't read >$fic< $!";
  if($flag){ while(<FIC>){ chomp; } $flag = '';}
  else{ $t = <FIC> ; }
  }
  }

elsif($choice eq 'E'){
#=================== reads all files until EndOfFile is reached (as choice A)
# but uses a C-style 'for' instead of 'for(@​A)'
  $n = @​A;
  for($i=0; $i < $n; $i++){
  $fic = $A[$i];
  $h++; print FOU "$h\t>$fic<\tchoice $choice\n";
  open FIC, $fic or die "Cant't read >$fic< $!";
  while(<FIC>){ chomp; }
  }
  }

#=================== reads all files until EndOfFile is reached (as choice A)
# but saves @​A then restores it
elsif($choice eq 'F'){
  @​S = @​A;
  for(@​A){
  $h++; print FOU "$h\t>$_<\tchoice $choice\n";
  $fic = $_;
  open FIC, $fic or die "Cant't read >$fic< $!";
  while(<FIC>){ chomp; }
  }
  @​A = @​S;
  }
#===================

# Prints the content of @​A after it was used
# ----------------------------------------------------
for(@​A){ print FOU "After​:file​:$_​:\n"}

########################################################################

sub litDir{ # finds all files of current directory which own some criteria​:
  # ordinary files the name of which finished with '.c'
  my ($rt) = @​_;
  opendir DIR, '.';
  @​$rt = grep { -f && /\.c$/ } readdir DIR;
  closedir DIR;
  }

@p5pRT
Copy link
Author

p5pRT commented Jul 5, 2005

From @schwern

[Jean-Luc.VERIT@​turbomeca.fr - Thu Oct 24 06​:06​:11 2002]​:

Hello
Here is a non logical behaviour (to my eyes) of Perl when I used an
array of names of files that I want to read.
I want to open and read all of them using

for\(@&#8203;myArray\)\{  \.\.\.  open FIL\,$\_   \.\.\.  read it with while\(\<FIL>\)\{

......} }

I don't modify the Array with a line of code, and when the loop
finishes, all values of @​myArray are null strings.

This is because you have used $_ twice and the second use clears it.
Here's what your code does​:

  my @​array = (1,2,3,4);
  for (@​array) {
  open FILE, "some/file";
  while(<FILE>) { }
  close FILE;
  }

  print @​array;

The @​array will be empty. Why? Because

  while(<FILE>) { }

is really

  while($_ = <FILE>) { }

but $_ is aliased to each element of @​array. So it gets blown over.

  The "foreach" modifier is an iterator​: it executes the statement once
  for each item in the LIST (with $_ aliased to each item in turn).

This allows code like this​:

  for (@​array) {
  s/something/something else/;
  }

which is equivalent to​:

  for my $idx (0..$#array) {
  $array[$idx] =~ s/something/something else/;
  }

The upshot is this​: Its not a bug. Don't use $_ in nested loops.

Also much of your reading of FIC is doing nothing.

  while(<FIC>){ chomp; }

This reads each line of the file, removes the trailing newline and then
throws the line away.

@p5pRT
Copy link
Author

p5pRT commented Jul 5, 2005

The RT System itself - Status changed from 'new' to 'open'

@p5pRT p5pRT closed this as completed Jul 5, 2005
@p5pRT
Copy link
Author

p5pRT commented Jul 5, 2005

@schwern - Status changed from 'open' to 'resolved'

@p5pRT
Copy link
Author

p5pRT commented Jul 5, 2005

From @schwern

[schwern - Mon Jul 04 22​:20​:52 2005]​:

but $_ is aliased to each element of @​array. So it gets blown over.

The "foreach" modifier is an iterator​: it executes the statement once
for each item in the LIST (with $_ aliased to each item in turn).

PS I belive this behavior was added in 5.004.

@p5pRT
Copy link
Author

p5pRT commented Jul 5, 2005

From Jean-Luc.VERIT@turbomeca.fr

I was convinced that the problem was about "$_". And I made my script
working whithout using "$_" for the array of files.

But
you told me "Dont used $_ in nested loops", But I wrote thousands lines of
Perl, and I used and abused using $_ in nested loops, and the
only time it didn't work is when it is used with this sequence.
first "$_" related to name of file from an array with a foreach,
second open this file,
third read this file with the second $_ and "while(<FIL>){ ....."

It is said some where in the Camel book (in the second and in the third
edition) that each loop has its own instance of "$_", and it always works
like this, but in the case I mentionned.

An other point (may be related to this) : I wrote about 2 or 3 hundred of
thousands lines of Perl, but I'm still confused with FILES in PERL. It seems
to me to be like a patch added to the language. It could be an explanation
of the problem, as the first instance of "$_"is created by a "foreach"
(which seems to me very robust), ans the second instance is created by the
"while(<FIL>){ ....."

Nevertheless thanks

----- Original Message -----
From​: "Michael G Schwern via RT" <perlbug-followup@​perl.org>
To​: <Jean-Luc.VERIT@​turbomeca.fr>
Sent​: Tuesday, July 05, 2005 7​:20 AM
Subject​: [perl #18073] [RESOLVED] Unwanted clearing of array member when
used as name of a file to be Read-opened (reach of EOF ???)

According to our records, your request regarding
"Unwanted clearing of array member when used as name of a file to be
Read-opened (reach of EOF ???)"
has been resolved.

If you have any further questions or concerns, please respond to this
message.

For other topics, please create a new ticket.

Please don't feel obligated to say "Thanks" or "Kudos" or "I owe you a
beer" -- if you respond to this message it will reopen the ticket. If you
must, please send email directly to the person who handled your ticket, and
not to the tracking system.

<URL​: https://rt-archive.perl.org/perl5/Ticket/Display.html?id=18073 >

@p5pRT
Copy link
Author

p5pRT commented Jul 5, 2005

From @schwern

On Tue, Jul 05, 2005 at 08​:05​:11AM +0200, Jean-Luc VERIT wrote​:

But
you told me "Dont used $_ in nested loops", But I wrote thousands lines of
Perl, and I used and abused using $_ in nested loops, and the
only time it didn't work is when it is used with this sequence.
first "$_" related to name of file from an array with a foreach,
second open this file,
third read this file with the second $_ and "while(<FIL>){ ....."

It is said some where in the Camel book (in the second and in the third
edition) that each loop has its own instance of "$_", and it always works
like this, but in the case I mentionned.

Only for loops auto-localize $_. A while loop has no intrinsic $_ assignment.
Its a bit of magic associated with the <FH> operator. This is the reason
you only seem to run into the problem while reading files, its rare to use
$_ in a while loop otherwise.

It may be worthwhile investigating if auto-localizing $_ in a while(<FH>)
construct is worth adding to the language.

Anyhow, stick to "foreach my $thing (@​things)" for anything but the smallest
loops and you'll be ok.

An other point (may be related to this) : I wrote about 2 or 3 hundred of
thousands lines of Perl, but I'm still confused with FILES in PERL. It seems
to me to be like a patch added to the language. It could be an explanation
of the problem, as the first instance of "$_"is created by a "foreach"
(which seems to me very robust), ans the second instance is created by the
"while(<FIL>){ ....."

Let's just say file handling is showing its age and hacks.

--
Michael G Schwern schwern@​pobox.com http​://www.pobox.com/~schwern
Just call me 'Moron Sugar'.
  http​://www.somethingpositive.net/sp05182002.shtml

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant