RE: Variable scope in wanted function
-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
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
-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
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
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