RE: Variable scope in wanted function

2004-10-12 Thread Ron Goral


 -Original Message-
 From: Jenda Krynicky [mailto:[EMAIL PROTECTED]
 Sent: Monday, October 11, 2004 10:39 AM
 To: [EMAIL PROTECTED]
 Subject: Re: Variable scope in wanted function


 From: Gunnar Hjalmarsson [EMAIL PROTECTED]
  Ron Goral wrote:
   I am having some difficulty with a module that is using File::Find.
   The method is below.
  
   The idea is to enter this method feeding it a file name and
   beginning directory and then looking for all occasions of
   $file_name and push those addresses into @a_files.  This works fine
   until I need to use FindPath again during the same session.  What
   I'm finding is that while @a_files looses scope within FindPath
   itself, it does not in ProcessFile.  In other words, when I exit
   FindPath and come back into it later, @a_files is an uninitiated
   array.  However when ProcessFile is called, @a_files has retained
   the values it had from the last call to FindPath.
  
   Am I making sense?
 
  Yes. But you are apparently running the code without warnings enabled,
  or else Perl would have indicated the reason for this problem.
 
   sub FindPath
   {
   #- Var Declaration And Initialization
   my ($hr_self, $file_name, $file_path) = @_;
   # Array to fill with file paths
   my @a_files = ();
  
   # Search file_path for the file
   find(\ProcessFile, $file_path);
  
   #- The Subroutine To Process Files And Directories
   sub ProcessFile
   {if ($_ eq $file_name){push (@a_files, $File::Find::name);}}
  
   # Return the paths found
   return @a_files;
   }   # end FindPath
 
  One possible solution is to move the ProcessFile() function out from
  FindPath(), so the former is no longer a nested sub:
 
   sub ProcessFile {
   my ($a_files, $file_name) = @_;
   push @$a_files, $File::Find::name if $_ eq $file_name;
   }
 
  and call ProcessFile() from FindPath() with arguments:
 
   find( \ProcessFile( [EMAIL PROTECTED], $file_name ), $file_path );

 You can't do that. You'd have to write it like this:

   find( sub {ProcessFile( [EMAIL PROTECTED], $file_name )}, $file_path );

 Another option would be to use an unnamed subroutine like this:

 sub FindPath
 {
 #- Var Declaration And Initialization
 my ($hr_self, $file_name, $file_path) = @_;
 # Array to fill with file paths
 my @a_files = ();

 # Search file_path for the file
 find(sub {
   if ($_ eq $file_name){push (@a_files, $File::Find::name);}
   }, $file_path);

 # Return the paths found
 return @a_files;
 }   # end FindPath


 Or (which might very well be fastest) you'd declare the $file_name
 and @a_files outside the FindPath and ProcessFile:

 {
   my ($file_name, @a_files);

   sub FindPath
 {
 #- Var Declaration And Initialization
   my ($hr_self, $file_path);
 ($hr_self, $file_name, $file_path) = @_;
 # Array to fill with file paths
 @a_files = ();

 # Search file_path for the file
 find(\ProcessFile, $file_path);

 # Return the paths found
 return @a_files;
   }   # end FindPath

   #- The Subroutine To Process Files And Directories
   sub ProcessFile {
 if ($_ eq $file_name){push (@a_files, $File::Find::name);}
   }
 }

 HTH, Jenda
 = [EMAIL PROTECTED] === http://Jenda.Krynicky.cz =
 When it comes to wine, women and song, wizards are allowed
 to get drunk and croon as much as they like.
   -- Terry Pratchett in Sourcery



Thanks to everyone who replied to this problem.

I discovered that what I had done, inadvertantly, was created a closure with
the ProcessFile function.  The closure will act on 'my' vars that are
created outside of its own scope, however, it will retain the values it
assigned to the var.  There is a much better explanation in Perl FAQ 7
(http://www.perldoc.com/perl5.8.4/pod/perlfaq7.html#What's-a-closure-).

This is how I ended up solving the issue:

sub FindPath
{
#- Var Declaration And Initialization
my ($hr_self, $file_name, $file_path) = @_;
#- Array to fill with file paths
my @a_files = ();

#- The Subroutine To Process Files And Directories
my $process_file = sub
{push (@a_files, $File::Find::name) if $_ eq $file_name;return;};

#- Search file_path Looking For This File
find(\$process_file, $file_path);

return @a_files;
}   # end FindPath

Now, the var $process_file is a coderef.  While having stumbled on this
closure business was pretty baffling, I'm glad I did.  It's an interesting
concept that I might could use advantageously in the future.

Thanks again -
Ron Goral



-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response




Re: Variable scope in wanted function

2004-10-11 Thread Jenda Krynicky
From: Gunnar Hjalmarsson [EMAIL PROTECTED]
 Ron Goral wrote:
  I am having some difficulty with a module that is using File::Find.
  The method is below.
  
  The idea is to enter this method feeding it a file name and
  beginning directory and then looking for all occasions of
  $file_name and push those addresses into @a_files.  This works fine
  until I need to use FindPath again during the same session.  What
  I'm finding is that while @a_files looses scope within FindPath
  itself, it does not in ProcessFile.  In other words, when I exit
  FindPath and come back into it later, @a_files is an uninitiated
  array.  However when ProcessFile is called, @a_files has retained
  the values it had from the last call to FindPath.
  
  Am I making sense?
 
 Yes. But you are apparently running the code without warnings enabled,
 or else Perl would have indicated the reason for this problem.
 
  sub FindPath
  {
  #- Var Declaration And Initialization
  my ($hr_self, $file_name, $file_path) = @_;
  # Array to fill with file paths
  my @a_files = ();
  
  # Search file_path for the file
  find(\ProcessFile, $file_path);
  
  #- The Subroutine To Process Files And Directories
  sub ProcessFile
  {if ($_ eq $file_name){push (@a_files, $File::Find::name);}}
  
  # Return the paths found
  return @a_files;
  }   # end FindPath
 
 One possible solution is to move the ProcessFile() function out from
 FindPath(), so the former is no longer a nested sub:
 
  sub ProcessFile {
  my ($a_files, $file_name) = @_;
  push @$a_files, $File::Find::name if $_ eq $file_name;
  }
 
 and call ProcessFile() from FindPath() with arguments:
 
  find( \ProcessFile( [EMAIL PROTECTED], $file_name ), $file_path );

You can't do that. You'd have to write it like this:

find( sub {ProcessFile( [EMAIL PROTECTED], $file_name )}, $file_path );

Another option would be to use an unnamed subroutine like this:

sub FindPath
{
#- Var Declaration And Initialization
my ($hr_self, $file_name, $file_path) = @_;
# Array to fill with file paths
my @a_files = ();

# Search file_path for the file
find(sub {
if ($_ eq $file_name){push (@a_files, $File::Find::name);}
}, $file_path);

# Return the paths found
return @a_files;
}   # end FindPath


Or (which might very well be fastest) you'd declare the $file_name 
and @a_files outside the FindPath and ProcessFile:

{
  my ($file_name, @a_files);

  sub FindPath
{
#- Var Declaration And Initialization
my ($hr_self, $file_path);
($hr_self, $file_name, $file_path) = @_;
# Array to fill with file paths
@a_files = ();

# Search file_path for the file
find(\ProcessFile, $file_path);

# Return the paths found
return @a_files;
  }   # end FindPath

  #- The Subroutine To Process Files And Directories
  sub ProcessFile {
if ($_ eq $file_name){push (@a_files, $File::Find::name);}
  }
}

HTH, Jenda
= [EMAIL PROTECTED] === http://Jenda.Krynicky.cz =
When it comes to wine, women and song, wizards are allowed 
to get drunk and croon as much as they like.
-- Terry Pratchett in Sourcery


-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response




RE: Variable scope in wanted function

2004-10-11 Thread Ron Goral


 -Original Message-
 From: Gunnar Hjalmarsson [mailto:[EMAIL PROTECTED]
 Sent: Sunday, October 10, 2004 6:32 PM
 To: [EMAIL PROTECTED]
 Subject: Re: Variable scope in wanted function


 Ron Goral wrote:
  I am having some difficulty with a module that is using File::Find.
  The method is below.
 
  The idea is to enter this method feeding it a file name and
  beginning directory and then looking for all occasions of
  $file_name and push those addresses into @a_files.  This works fine
  until I need to use FindPath again during the same session.  What
  I'm finding is that while @a_files looses scope within FindPath
  itself, it does not in ProcessFile.  In other words, when I exit
  FindPath and come back into it later, @a_files is an uninitiated
  array.  However when ProcessFile is called, @a_files has retained
  the values it had from the last call to FindPath.
 
  Am I making sense?

 Yes. But you are apparently running the code without warnings enabled,
 or else Perl would have indicated the reason for this problem.

  sub FindPath
  {
  #- Var Declaration And Initialization
  my ($hr_self, $file_name, $file_path) = @_;
  # Array to fill with file paths
  my @a_files = ();
 
  # Search file_path for the file
  find(\ProcessFile, $file_path);
 
  #- The Subroutine To Process Files And Directories
  sub ProcessFile
  {if ($_ eq $file_name){push (@a_files, $File::Find::name);}}
 
  # Return the paths found
  return @a_files;
  }   # end FindPath

 One possible solution is to move the ProcessFile() function out from
 FindPath(), so the former is no longer a nested sub:

  sub ProcessFile {
  my ($a_files, $file_name) = @_;
  push @$a_files, $File::Find::name if $_ eq $file_name;
  }

 and call ProcessFile() from FindPath() with arguments:

  find( \ProcessFile( [EMAIL PROTECTED], $file_name ), $file_path );

 And last but not least:

  use warnings;

 ;-)

 --
 Gunnar Hjalmarsson
 Email: http://www.gunnar.cc/cgi-bin/contact.pl

Actually, I am using warnings. However, in the 'real' code, I have placed
the the call to 'find' within an eval block so that I can manage the errors.
Is this why I did not receive any warnings? The difficulties with moving
ProcessFile out of FindPath is that any return values ProcessFile might have
are ignored and it can take no arguments (this is from
http://search.cpan.org/~nwclark/perl-5.8.5/lib/File/Find.pm#The_wanted_funct
ion).

I've setting up a global variable like $hr_self-{a_files}, where $hr_self
is an object ref to the module.  This requires calling ProcessFile like so:

find(\$hr_self-ProcessFile, $file_path);
or
find(\ProcessFile($hr_self), $file_path);

File::Find dies here with the complaint invalid top directory at
/usr/lib/perl5/5.6.1/File/Find.pm line 295, line 36.  I'm fairly certain
this is because of the '$hr_self-'.  I'm also completely out of ideas for
this.  At least when ProcessFile is defined within FindPath, the only
variable trouble I had was with @a_files.

There is a light, however.  If ProcessFile is actually an anonymous sub and
called this way:

my $processfile = sub {if ($_ eq $file_name){push (@a_files,
$File::Find::name);}};

find(\$processfile, $file_path);

There are no errors and @a_files is populated (and depopulated) as it should
be.

Thanks for taking the time to check this out and to write an answer.



-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response




Re: Variable scope in wanted function

2004-10-11 Thread Gunnar Hjalmarsson
Ron Goral wrote:
Gunnar Hjalmarsson wrote:
One possible solution is to move the ProcessFile() function out
from FindPath(), so the former is no longer a nested sub:
sub ProcessFile {
my ($a_files, $file_name) = @_;
push @$a_files, $File::Find::name if $_ eq $file_name;
}
and call ProcessFile() from FindPath() with arguments:
find( \ProcessFile( [EMAIL PROTECTED], $file_name ), $file_path );
And last but not least:
use warnings;
;-)
Actually, I am using warnings. However, in the 'real' code, I have
placed the the call to 'find' within an eval block so that I can
manage the errors. Is this why I did not receive any warnings?
I get the same warnings also with such an eval block.
The difficulties with moving ProcessFile out of FindPath is that
any return values ProcessFile might have are ignored and it can
take no arguments (this is from 
http://search.cpan.org/~nwclark/perl-5.8.5/lib/File/Find.pm#The_wanted_function).
No return values does not matter, since my suggestion didn't make use
of return values from ProcessFile, but the rest does. Jenda showed us
a way to modify that approach to working code.
Sorry for posting non-tested code. :(
snip
There is a light, however.  If ProcessFile is actually an anonymous
sub and called this way:
my $processfile = sub {if ($_ eq $file_name){push (@a_files, 
$File::Find::name);}};

find(\$processfile, $file_path);
There are no errors and @a_files is populated (and depopulated) as
it should be.
Yes, that seems to be a nice solution. You can even pass it to find()
by just saying:
find( $ProcessFile, $file_path );
If you haven't already, to get an understanding of what the original
problem actually was about, you can read the Variable '%s' will not
stay shared section in perldoc perldiag.
--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl
--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response



Re: Variable scope in wanted function

2004-10-10 Thread Gunnar Hjalmarsson
Ron Goral wrote:
I am having some difficulty with a module that is using File::Find.
The method is below.
The idea is to enter this method feeding it a file name and
beginning directory and then looking for all occasions of
$file_name and push those addresses into @a_files.  This works fine
until I need to use FindPath again during the same session.  What
I'm finding is that while @a_files looses scope within FindPath
itself, it does not in ProcessFile.  In other words, when I exit
FindPath and come back into it later, @a_files is an uninitiated 
array.  However when ProcessFile is called, @a_files has retained
the values it had from the last call to FindPath.

Am I making sense?
Yes. But you are apparently running the code without warnings enabled,
or else Perl would have indicated the reason for this problem.
sub FindPath
{
#- Var Declaration And Initialization
my ($hr_self, $file_name, $file_path) = @_;
# Array to fill with file paths
my @a_files = ();
# Search file_path for the file
find(\ProcessFile, $file_path);
#- The Subroutine To Process Files And Directories
sub ProcessFile
{if ($_ eq $file_name){push (@a_files, $File::Find::name);}}
# Return the paths found
return @a_files;
}   # end FindPath
One possible solution is to move the ProcessFile() function out from
FindPath(), so the former is no longer a nested sub:
sub ProcessFile {
my ($a_files, $file_name) = @_;
push @$a_files, $File::Find::name if $_ eq $file_name;
}
and call ProcessFile() from FindPath() with arguments:
find( \ProcessFile( [EMAIL PROTECTED], $file_name ), $file_path );
And last but not least:
use warnings;
;-)
--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl
--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response